From a57c4b92d14e8ef56e410755a6f2e3f7fc766506 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 24 Aug 2024 16:52:08 +0300 Subject: [PATCH 01/15] SPARK-2341 AccountCreationWizard: make the domain as a first field --- .../jivesoftware/AccountCreationWizard.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 67b07b5e1..8cb283ccf 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -59,14 +59,15 @@ */ public class AccountCreationWizard extends JPanel { private static final long serialVersionUID = -7808507939643878212L; + + private final JTextField serverField = new JTextField(); + private final JTextField usernameField = new JTextField(); private final JPasswordField passwordField = new JPasswordField(); private final JPasswordField confirmPasswordField = new JPasswordField(); - private final JTextField serverField = new JTextField(); - private final JButton createAccountButton = new JButton(); private JDialog dialog; @@ -80,30 +81,30 @@ public class AccountCreationWizard extends JPanel { */ public AccountCreationWizard() { // Associate Mnemonics + JLabel serverLabel = new JLabel(); + ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); JLabel usernameLabel = new JLabel(); ResourceUtils.resLabel( usernameLabel, usernameField, Res.getString("label.username") + ":"); JLabel passwordLabel = new JLabel(); ResourceUtils.resLabel( passwordLabel, passwordField, Res.getString("label.password") + ":"); JLabel confirmPasswordLabel = new JLabel(); ResourceUtils.resLabel( confirmPasswordLabel, confirmPasswordField, Res.getString("label.confirm.password") + ":"); - JLabel serverLabel = new JLabel(); - ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account")); setLayout(new GridBagLayout()); // Add component to UI - add( usernameLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(usernameField, new GridBagConstraints(1, 0, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0)); + add( serverLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(serverField, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add( passwordLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(passwordField, new GridBagConstraints(1, 1, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add( usernameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(usernameField, new GridBagConstraints(1, 1, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0)); - add( confirmPasswordLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(confirmPasswordField, new GridBagConstraints(1, 2, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add( passwordLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(passwordField, new GridBagConstraints(1, 2, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add( serverLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(serverField, new GridBagConstraints(1, 3, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add( confirmPasswordLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(confirmPasswordField, new GridBagConstraints(1, 3, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); progressBar = new JProgressBar(); From d6567e55bd4918ad078a09b4abb2311213420b1a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 24 Aug 2024 17:48:06 +0300 Subject: [PATCH 02/15] SPARK-2341 AccountCreationWizard: make serverField as a combo box with providers Make it easier for user to pick a server. Hardcode providers list, for now only A class. --- .../jivesoftware/AccountCreationWizard.java | 15 +++-- .../java/org/jivesoftware/XmppProviders.java | 60 +++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/org/jivesoftware/XmppProviders.java diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 8cb283ccf..03ef6462d 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -60,7 +60,7 @@ public class AccountCreationWizard extends JPanel { private static final long serialVersionUID = -7808507939643878212L; - private final JTextField serverField = new JTextField(); + private final JComboBox serverField = new JComboBox<>(); private final JTextField usernameField = new JTextField(); @@ -81,6 +81,9 @@ public class AccountCreationWizard extends JPanel { */ public AccountCreationWizard() { // Associate Mnemonics + serverField.setEditable(true); + serverField.setModel(XmppProviders.getXmppProvidersModel()); + JLabel serverLabel = new JLabel(); ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); JLabel usernameLabel = new JLabel(); @@ -166,7 +169,8 @@ public String getConfirmPassword() { * @return the server to use. */ public String getServer() { - return serverField.getText(); + String selectedServer = (String) serverField.getSelectedItem(); + return selectedServer != null ? selectedServer.trim() : ""; } /** @@ -185,6 +189,7 @@ private void createAccount() { boolean errors = false; String errorMessage = ""; + String server = getServer(); if (!ModelUtil.hasLength(getUsername())) { errors = true; usernameField.requestFocus(); @@ -198,7 +203,7 @@ else if (!ModelUtil.hasLength(getConfirmPassword())) { errors = true; errorMessage = Res.getString("message.confirmation.password.error"); } - else if (!ModelUtil.hasLength(getServer())) { + else if (!ModelUtil.hasLength(server)) { errors = true; errorMessage = Res.getString("message.account.error"); } @@ -216,7 +221,7 @@ else if (!isPasswordValid()) { final Component ui = this; progressBar.setIndeterminate(true); progressBar.setStringPainted(true); - progressBar.setString(Res.getString("message.registering", getServer())); + progressBar.setString(Res.getString("message.registering", server)); progressBar.setVisible(true); final SwingWorker worker = new SwingWorker() { @@ -259,7 +264,7 @@ public void finished() { if (ui.isShowing()) { createAccountButton.setEnabled(true); UIManager.put("OptionPane.okButtonText", Res.getString("ok")); - JOptionPane.showMessageDialog(ui, Res.getString("message.connection.failed", getServer()) + JOptionPane.showMessageDialog(ui, Res.getString("message.connection.failed", server) + "\n" + th, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); createAccountButton.setEnabled(true); } diff --git a/core/src/main/java/org/jivesoftware/XmppProviders.java b/core/src/main/java/org/jivesoftware/XmppProviders.java new file mode 100644 index 000000000..fb69b6717 --- /dev/null +++ b/core/src/main/java/org/jivesoftware/XmppProviders.java @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2004-2024 Jive Software. All rights reserved. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.jivesoftware; + +import javax.swing.*; + +import java.util.Random; + + +public class XmppProviders { + /** + * Providers A + * Disabled providers that requires a CAPTCHA + */ + private static final String[] providers = new String[]{ +// "07f.de", +// "chalec.org", +// "chapril.org", +// "chatrix.one", +// "draugr.de", +// "hookipa.net", + "jabber.fr", +// "macaw.me", +// "magicbroccoli.de", +// "nixnet.services", +// "projectsegfau.lt", +// "redlibre.es", +// "suchat.org", +// "sure.im", +// "trashserver.net", + "xmpp.earth", + "yax.im", + }; + + public static ComboBoxModel getXmppProvidersModel() { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(); + for (String provider : providers) { + model.addElement(provider); + } + // Randomly pre-select a provider + int randomProviderIdx = new Random().nextInt(providers.length); + model.setSelectedItem(providers[randomProviderIdx]); + return model; + } +} From abcdc21145068ca86850d79be89436a136c50481 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 24 Aug 2024 18:43:16 +0300 Subject: [PATCH 03/15] SPARK-2341 Rename Accounts button to Sign Up Also rename the btnCreateAccount to btnSignUp and createAccountButton to signUpButton --- .../java/org/jivesoftware/LoginDialog.java | 10 +++---- .../org/jivesoftware/gui/LoginUIPanel.form | 4 +-- .../org/jivesoftware/gui/LoginUIPanel.java | 30 +++++++++---------- .../main/resources/i18n/spark_i18n.properties | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/LoginDialog.java b/core/src/main/java/org/jivesoftware/LoginDialog.java index ed24cb482..95cb1f957 100644 --- a/core/src/main/java/org/jivesoftware/LoginDialog.java +++ b/core/src/main/java/org/jivesoftware/LoginDialog.java @@ -383,7 +383,7 @@ private final class LoginPanel extends JPanel implements KeyListener, ActionList private final JCheckBox loginAsInvisibleBox = new JCheckBox(); private final JCheckBox loginAnonymouslyBox = new JCheckBox(); - private final RolloverButton createAccountButton = new RolloverButton(); + private final RolloverButton signUpButton = new RolloverButton(); private final RolloverButton passwordResetButton = new RolloverButton(); private final JLabel progressBar = new JLabel(); @@ -410,7 +410,7 @@ private final class LoginPanel extends JPanel implements KeyListener, ActionList ResourceUtils.resButton(savePasswordBox, Res.getString("checkbox.save.password")); ResourceUtils.resButton(autoLoginBox, Res.getString("checkbox.auto.login")); ResourceUtils.resLabel(serverLabel, serverField, Res.getString("label.server")); - ResourceUtils.resButton(createAccountButton, Res.getString("label.accounts")); + ResourceUtils.resButton(signUpButton, Res.getString("label.accounts")); ResourceUtils.resButton(passwordResetButton, Res.getString("label.passwordreset")); ResourceUtils.resButton(loginAsInvisibleBox, Res.getString("checkbox.login.as.invisible")); ResourceUtils.resButton(loginAnonymouslyBox, Res.getString("checkbox.login.anonymously")); @@ -515,7 +515,7 @@ private final class LoginPanel extends JPanel implements KeyListener, ActionList loginAnonymouslyBox.addActionListener(this); if (!Default.getBoolean(Default.ACCOUNT_DISABLED) && localPref.getAccountsReg()) { - buttonPanel.add(createAccountButton, + buttonPanel.add(signUpButton, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0)); } @@ -665,7 +665,7 @@ public void mouseClicked(MouseEvent e) { validateLogin(); } - createAccountButton.addActionListener(this); + signUpButton.addActionListener(this); final String lockedDownURL = Default.getString(Default.HOST_NAME); if (ModelUtil.hasLength(lockedDownURL)) { @@ -728,7 +728,7 @@ boolean isLoginAsInvisible() { public void actionPerformed(ActionEvent e) { if (e.getSource() == quitButton) { quitLogin(); - } else if (e.getSource() == createAccountButton) { + } else if (e.getSource() == signUpButton) { AccountCreationWizard createAccountPanel = new AccountCreationWizard(); createAccountPanel.invoke(loginDialog); diff --git a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.form b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.form index a15b29014..cd40c59ef 100644 --- a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.form +++ b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.form @@ -252,12 +252,12 @@ - + - + diff --git a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java index ab564fbbf..dc9f41199 100644 --- a/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java +++ b/core/src/main/java/org/jivesoftware/gui/LoginUIPanel.java @@ -183,7 +183,7 @@ private void init() { ResourceUtils.resButton(cbSavePassword, Res.getString("checkbox.save.password")); ResourceUtils.resButton(cbAutoLogin, Res.getString("checkbox.auto.login")); - ResourceUtils.resButton(btnCreateAccount, Res.getString("label.accounts")); + ResourceUtils.resButton(btnSignUp, Res.getString("label.accounts")); ResourceUtils.resButton(cbLoginInvisible, Res.getString("checkbox.login.as.invisible")); ResourceUtils.resButton(cbAnonymous, Res.getString("checkbox.login.anonymously")); ResourceUtils.resButton(btnReset, Res.getString("label.passwordreset")); @@ -305,7 +305,7 @@ public void mouseClicked(MouseEvent e) { TaskEngine.getInstance().submit(this::login); } - btnCreateAccount.addActionListener(this); + btnSignUp.addActionListener(this); final String lockedDownURL = Default.getString(Default.HOST_NAME); if (ModelUtil.hasLength(lockedDownURL)) { @@ -314,7 +314,7 @@ public void mouseClicked(MouseEvent e) { //reset ui //btnAdvanced.setUI(new BasicButtonUI()); - //btnCreateAccount.setUI(new BasicButtonUI()); + //btnSignUp.setUI(new BasicButtonUI()); tfDomain.putClientProperty("JTextField.placeholderText", Res.getString("hint.login.domain")); tfPassword.putClientProperty("JTextField.placeholderText", Res.getString("hint.login.password")); tfUsername.putClientProperty("JTextField.placeholderText", Res.getString("hint.login.username")); @@ -355,7 +355,7 @@ private void configureVisibility() { } if (Default.getBoolean(Default.ACCOUNT_DISABLED) || !localPref.getAccountsReg()) { - pnlBtns.remove(btnCreateAccount); + pnlBtns.remove(btnSignUp); height = height + 15; } @@ -397,7 +397,7 @@ private void initComponents() { cbAnonymous = new javax.swing.JCheckBox(); pnlBtns = new javax.swing.JPanel(); btnLogin = new javax.swing.JButton(); - btnCreateAccount = new javax.swing.JButton(); + btnSignUp = new javax.swing.JButton(); btnAdvanced = new javax.swing.JButton(); btnReset = new javax.swing.JButton(); @@ -504,13 +504,13 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); pnlBtns.add(btnLogin); - btnCreateAccount.setBackground(new java.awt.Color(255, 255, 255)); - btnCreateAccount.setText("Account"); - btnCreateAccount.setBorderPainted(false); - btnCreateAccount.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - btnCreateAccount.setOpaque(false); - btnCreateAccount.setPreferredSize(new java.awt.Dimension(95, 28)); - pnlBtns.add(btnCreateAccount); + btnSignUp.setBackground(new java.awt.Color(255, 255, 255)); + btnSignUp.setText("Account"); + btnSignUp.setBorderPainted(false); + btnSignUp.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + btnSignUp.setOpaque(false); + btnSignUp.setPreferredSize(new java.awt.Dimension(95, 28)); + pnlBtns.add(btnSignUp); btnAdvanced.setBackground(new java.awt.Color(255, 255, 255)); btnAdvanced.setText("Advanced"); @@ -569,7 +569,7 @@ private void btnResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnAdvanced; - private javax.swing.JButton btnCreateAccount; + private javax.swing.JButton btnSignUp; private javax.swing.JButton btnLogin; private javax.swing.JButton btnReset; private javax.swing.JCheckBox cbAnonymous; @@ -910,7 +910,7 @@ boolean isLoginAsInvisible() { */ @Override public void actionPerformed(ActionEvent e) { - if (e.getSource() == btnCreateAccount) { + if (e.getSource() == btnSignUp) { AccountCreationWizard createAccountPanel = new AccountCreationWizard(); createAccountPanel.invoke(loginDialog); @@ -1055,7 +1055,7 @@ private void setComponentsAvailable(boolean available) cbAnonymous.setEnabled(available); btnLogin.setEnabled(available); btnAdvanced.setEnabled(available); - btnCreateAccount.setEnabled(available); + btnSignUp.setEnabled(available); // Need to set both editable and enabled for best behavior. tfUsername.setEditable(available); diff --git a/core/src/main/resources/i18n/spark_i18n.properties b/core/src/main/resources/i18n/spark_i18n.properties index 6b35d136b..879daf587 100644 --- a/core/src/main/resources/i18n/spark_i18n.properties +++ b/core/src/main/resources/i18n/spark_i18n.properties @@ -224,7 +224,7 @@ group.encryption_mode = Encryption mode label.na = n/a label.home = Home -label.accounts = A&ccounts +label.accounts = Sign Up label.add.conference.service = Add conference service label.add.jid = Add JID label.add.task = Add task From d0ec2c7e65abbe35824e46861ffe80ec879745ad Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 17:03:22 +0300 Subject: [PATCH 04/15] AccountCreationWizard: init components and only then build layout Signed-off-by: Sergey Ponomarev --- .../jivesoftware/AccountCreationWizard.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 03ef6462d..8b108f551 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -93,9 +93,16 @@ public AccountCreationWizard() { JLabel confirmPasswordLabel = new JLabel(); ResourceUtils.resLabel( confirmPasswordLabel, confirmPasswordField, Res.getString("label.confirm.password") + ":"); ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account")); + createAccountButton.addActionListener( actionEvent -> createAccount() ); - setLayout(new GridBagLayout()); + progressBar = new JProgressBar(); + progressBar.setVisible(false); + JButton closeButton = new JButton(); + ResourceUtils.resButton( closeButton, Res.getString("button.close")); + closeButton.addActionListener( actionEvent -> dialog.dispose() ); + + setLayout(new GridBagLayout()); // Add component to UI add( serverLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); add(serverField, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); @@ -109,22 +116,10 @@ public AccountCreationWizard() { add( confirmPasswordLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); add(confirmPasswordField, new GridBagConstraints(1, 3, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - progressBar = new JProgressBar(); - - - add(progressBar, new GridBagConstraints(1, 4, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - progressBar.setVisible(false); + add(progressBar, new GridBagConstraints(1, 5, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); add(createAccountButton, new GridBagConstraints(2, 5, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - - JButton closeButton = new JButton(); - ResourceUtils.resButton( closeButton, Res.getString("button.close")); add( closeButton, new GridBagConstraints(3, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - - - createAccountButton.addActionListener( actionEvent -> createAccount() ); - - closeButton.addActionListener( actionEvent -> dialog.dispose() ); } /** From 46ce0dae15e29bd5957acbb2dc7b57c322db353a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 17:42:39 +0300 Subject: [PATCH 05/15] AccountCreationWizard: extract fields to a separate formPanel Signed-off-by: Sergey Ponomarev --- .../jivesoftware/AccountCreationWizard.java | 71 +++++++++++-------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 8b108f551..59f94cb28 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -62,20 +62,44 @@ public class AccountCreationWizard extends JPanel { private final JComboBox serverField = new JComboBox<>(); - private final JTextField usernameField = new JTextField(); - - private final JPasswordField passwordField = new JPasswordField(); - - private final JPasswordField confirmPasswordField = new JPasswordField(); - private final JButton createAccountButton = new JButton(); + private final FormPanel formPanel = new FormPanel(); + private JDialog dialog; private boolean registered; private XMPPConnection connection = null; private final JProgressBar progressBar; + static class FormPanel extends JPanel { + private final JTextField usernameField = new JTextField(); + + private final JPasswordField passwordField = new JPasswordField(); + + private final JPasswordField confirmPasswordField = new JPasswordField(); + + public FormPanel() { + super(); + JLabel usernameLabel = new JLabel(); + ResourceUtils.resLabel( usernameLabel, usernameField, Res.getString("label.username") + ":"); + JLabel passwordLabel = new JLabel(); + ResourceUtils.resLabel( passwordLabel, passwordField, Res.getString("label.password") + ":"); + JLabel confirmPasswordLabel = new JLabel(); + ResourceUtils.resLabel( confirmPasswordLabel, confirmPasswordField, Res.getString("label.confirm.password") + ":"); + + setLayout(new GridBagLayout()); + add( usernameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(usernameField, new GridBagConstraints(1, 1, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0)); + + add( passwordLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(passwordField, new GridBagConstraints(1, 2, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + + add( confirmPasswordLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(confirmPasswordField, new GridBagConstraints(1, 3, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + } + } + /** * Construct the AccountCreationWizard UI. */ @@ -86,12 +110,6 @@ public AccountCreationWizard() { JLabel serverLabel = new JLabel(); ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); - JLabel usernameLabel = new JLabel(); - ResourceUtils.resLabel( usernameLabel, usernameField, Res.getString("label.username") + ":"); - JLabel passwordLabel = new JLabel(); - ResourceUtils.resLabel( passwordLabel, passwordField, Res.getString("label.password") + ":"); - JLabel confirmPasswordLabel = new JLabel(); - ResourceUtils.resLabel( confirmPasswordLabel, confirmPasswordField, Res.getString("label.confirm.password") + ":"); ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account")); createAccountButton.addActionListener( actionEvent -> createAccount() ); @@ -107,19 +125,12 @@ public AccountCreationWizard() { add( serverLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); add(serverField, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add( usernameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(usernameField, new GridBagConstraints(1, 1, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0)); - - add( passwordLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(passwordField, new GridBagConstraints(1, 2, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - - add( confirmPasswordLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add(confirmPasswordField, new GridBagConstraints(1, 3, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add(formPanel, new GridBagConstraints(0, 2, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); - add(progressBar, new GridBagConstraints(1, 5, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add(createAccountButton, new GridBagConstraints(2, 5, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(progressBar, new GridBagConstraints(1, 3, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add(createAccountButton, new GridBagConstraints(2, 4, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add( closeButton, new GridBagConstraints(3, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add( closeButton, new GridBagConstraints(3, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); } /** @@ -128,7 +139,7 @@ public AccountCreationWizard() { * @return the username. */ public String getUsername() { - return XmppStringUtils.escapeLocalpart(usernameField.getText().toLowerCase()); + return XmppStringUtils.escapeLocalpart(formPanel.usernameField.getText().toLowerCase()); } /** @@ -137,7 +148,7 @@ public String getUsername() { * @return the username. */ public String getUsernameWithoutEscape() { - return usernameField.getText(); + return formPanel.usernameField.getText(); } /** @@ -146,7 +157,7 @@ public String getUsernameWithoutEscape() { * @return the password to use for the new account. */ public String getPassword() { - return new String(passwordField.getPassword()); + return new String(formPanel.passwordField.getPassword()); } /** @@ -155,7 +166,7 @@ public String getPassword() { * @return the password to use for the new account. */ public String getConfirmPassword() { - return new String(confirmPasswordField.getPassword()); + return new String(formPanel.confirmPasswordField.getPassword()); } /** @@ -187,7 +198,7 @@ private void createAccount() { String server = getServer(); if (!ModelUtil.hasLength(getUsername())) { errors = true; - usernameField.requestFocus(); + formPanel.usernameField.requestFocus(); errorMessage = Res.getString("message.username.error"); } else if (!ModelUtil.hasLength(getPassword())) { @@ -287,8 +298,8 @@ private void accountCreationFailed( StanzaError.Condition condition ) { String message; if (condition == StanzaError.Condition.conflict) { message = Res.getString("message.already.exists"); - usernameField.setText(""); - usernameField.requestFocus(); + formPanel.usernameField.setText(""); + formPanel.usernameField.requestFocus(); } else if (condition == StanzaError.Condition.not_allowed || condition == StanzaError.Condition.forbidden) { message = Res.getString("message.create.account.not.allowed"); } else { From fb5deff67a0755c419f9d6193ad549ec24a0b487 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 18:06:28 +0300 Subject: [PATCH 06/15] AccountCreationWizard: if registration not allowed the Prosody return service_unavailable Similar to 2913b3c27233a9d6914bcd10039ae512c6906ee8 Signed-off-by: Sergey Ponomarev --- core/src/main/java/org/jivesoftware/AccountCreationWizard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 59f94cb28..36c86b168 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -300,7 +300,7 @@ private void accountCreationFailed( StanzaError.Condition condition ) { message = Res.getString("message.already.exists"); formPanel.usernameField.setText(""); formPanel.usernameField.requestFocus(); - } else if (condition == StanzaError.Condition.not_allowed || condition == StanzaError.Condition.forbidden) { + } else if (condition == StanzaError.Condition.not_allowed || condition == StanzaError.Condition.forbidden || condition == StanzaError.Condition.service_unavailable) { message = Res.getString("message.create.account.not.allowed"); } else { message = Res.getString("message.create.account"); From a5041c5929c9febaf255ebf30cbce1ef8b6a2b6f Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 18:18:24 +0300 Subject: [PATCH 07/15] SPARK-2341 AccountCreationWizard: Start registration button to check if registration is allowed Signed-off-by: Sergey Ponomarev --- .../jivesoftware/AccountCreationWizard.java | 59 +++++++++++++++++-- .../main/resources/i18n/spark_i18n.properties | 1 + 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 36c86b168..ba515c9d3 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -62,10 +62,14 @@ public class AccountCreationWizard extends JPanel { private final JComboBox serverField = new JComboBox<>(); - private final JButton createAccountButton = new JButton(); + private final JButton startRegistrationButton = new JButton(); + + private final JLabel instructionsLabel = new JLabel(); private final FormPanel formPanel = new FormPanel(); + private final JButton createAccountButton = new JButton(); + private JDialog dialog; private boolean registered; @@ -108,9 +112,15 @@ public AccountCreationWizard() { serverField.setEditable(true); serverField.setModel(XmppProviders.getXmppProvidersModel()); + ResourceUtils.resButton(startRegistrationButton, Res.getString("button.start.registration")); + startRegistrationButton.addActionListener( actionEvent -> startRegistration() ); + + formPanel.setVisible(false); + JLabel serverLabel = new JLabel(); ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account")); + createAccountButton.setEnabled(false); createAccountButton.addActionListener( actionEvent -> createAccount() ); progressBar = new JProgressBar(); @@ -124,13 +134,16 @@ public AccountCreationWizard() { // Add component to UI add( serverLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); add(serverField, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add(startRegistrationButton, new GridBagConstraints(1, 1, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add(formPanel, new GridBagConstraints(0, 2, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); + add(instructionsLabel, new GridBagConstraints(0, 2, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); - add(progressBar, new GridBagConstraints(1, 3, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add(createAccountButton, new GridBagConstraints(2, 4, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(formPanel, new GridBagConstraints(0, 3, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); - add( closeButton, new GridBagConstraints(3, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(progressBar, new GridBagConstraints(1, 4, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + + add(createAccountButton, new GridBagConstraints(2, 5, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add( closeButton, new GridBagConstraints(3, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); } /** @@ -188,6 +201,42 @@ public boolean isPasswordValid() { return getPassword().equals(getConfirmPassword()); } + /** + * Start registration and fetch signup form. + */ + private void startRegistration() { + final Component ui = this; + try { + connection = getConnection(); + } catch (SmackException | IOException | XMPPException e) { + String th = e.getCause() == null ? e.getMessage() : e.getCause().getMessage(); + JOptionPane.showMessageDialog(ui, Res.getString("message.connection.failed", getServer()) + + "\n" + th, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); + return; + } + try { + final AccountManager accountManager = AccountManager.getInstance(connection); + if (accountManager.supportsAccountCreation()) { + formPanel.setVisible(true); + createAccountButton.setEnabled(true); + String instructions = accountManager.getAccountInstructions(); + instructionsLabel.setText(instructions); + } else { + String message = Res.getString("message.create.account.not.allowed"); + JOptionPane.showMessageDialog(this, message, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); + } + } catch (XMPPException | SmackException | InterruptedException e) { + StanzaError.Condition condition = null; + if (e instanceof XMPPException.XMPPErrorException) { + condition = ((XMPPException.XMPPErrorException) e).getStanzaError().getCondition(); + } + if (condition == null) { + condition = StanzaError.Condition.internal_server_error; + } + accountCreationFailed(condition); + } + } + /** * Creates the new account using the supplied information. */ diff --git a/core/src/main/resources/i18n/spark_i18n.properties b/core/src/main/resources/i18n/spark_i18n.properties index 879daf587..b4c417de0 100644 --- a/core/src/main/resources/i18n/spark_i18n.properties +++ b/core/src/main/resources/i18n/spark_i18n.properties @@ -90,6 +90,7 @@ button.cert.info = Details button.clear = Clear button.close = Close button.copy.to.clipboard = Copy to clipboard +button.start.registration = Start registration button.create.account = Create account button.create.room = Create or join room button.decline = Decline From 53f544fe76056ab846f196c2b39f641218124fc4 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 19:52:00 +0300 Subject: [PATCH 08/15] AccountCreationWizard: add empty line in layout for adding a new panel Signed-off-by: Sergey Ponomarev --- .../main/java/org/jivesoftware/AccountCreationWizard.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index ba515c9d3..7803dce23 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -134,16 +134,17 @@ public AccountCreationWizard() { // Add component to UI add( serverLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); add(serverField, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add(startRegistrationButton, new GridBagConstraints(1, 1, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); add(instructionsLabel, new GridBagConstraints(0, 2, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); add(formPanel, new GridBagConstraints(0, 3, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); - add(progressBar, new GridBagConstraints(1, 4, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); + add(progressBar, new GridBagConstraints(1, 6, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add(createAccountButton, new GridBagConstraints(2, 5, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add( closeButton, new GridBagConstraints(3, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(createAccountButton, new GridBagConstraints(2, 6, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add( closeButton, new GridBagConstraints(3, 6, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); } /** From 3952d4b33c10f415b6af3c9205aa10cd7d013969 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Mon, 26 Aug 2024 19:55:33 +0300 Subject: [PATCH 09/15] SPARK-2341 AccountCreationWizard: Show additional registration fields Signed-off-by: Sergey Ponomarev --- .../jivesoftware/AccountCreationWizard.java | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 7803dce23..67abbd827 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -20,13 +20,18 @@ import org.jivesoftware.resource.Res; import org.jivesoftware.smack.*; import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode; +import org.jivesoftware.smack.filter.StanzaIdFilter; import org.jivesoftware.smack.packet.StanzaError; import org.jivesoftware.smack.parsing.ExceptionLoggingCallback; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.jivesoftware.smack.util.DNSUtil; import org.jivesoftware.smackx.iqregister.AccountManager; +import org.jivesoftware.smackx.iqregister.packet.Registration; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jivesoftware.spark.component.TitlePanel; +import org.jivesoftware.spark.ui.DataFormUI; import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; @@ -51,6 +56,9 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.UnrecoverableKeyException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.ONLY_SERVER_SIDE; @@ -68,10 +76,14 @@ public class AccountCreationWizard extends JPanel { private final FormPanel formPanel = new FormPanel(); + private final JPanel formPanelFields = new JPanel(); + private final JButton createAccountButton = new JButton(); private JDialog dialog; + private DataFormUI registrationForm; + private boolean registered; private XMPPConnection connection = null; private final JProgressBar progressBar; @@ -116,6 +128,7 @@ public AccountCreationWizard() { startRegistrationButton.addActionListener( actionEvent -> startRegistration() ); formPanel.setVisible(false); + formPanelFields.setVisible(false); JLabel serverLabel = new JLabel(); ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); @@ -141,6 +154,8 @@ public AccountCreationWizard() { add(formPanel, new GridBagConstraints(0, 3, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); + add(formPanelFields, new GridBagConstraints(0, 4, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); + add(progressBar, new GridBagConstraints(1, 6, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); add(createAccountButton, new GridBagConstraints(2, 6, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); @@ -222,6 +237,11 @@ private void startRegistration() { createAccountButton.setEnabled(true); String instructions = accountManager.getAccountInstructions(); instructionsLabel.setText(instructions); + registrationForm = getRegistrationForm(); + if (registrationForm != null) { + formPanelFields.add(registrationForm); + formPanelFields.setVisible(true); + } } else { String message = Res.getString("message.create.account.not.allowed"); JOptionPane.showMessageDialog(this, message, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); @@ -238,6 +258,37 @@ private void startRegistration() { } } + private DataFormUI getRegistrationForm() { + Registration info = getRegistrationInfo(); + if (info == null) { + return null; + } + DataForm regFields = info.getExtension(DataForm.class); + if (regFields == null) { + return null; + } + // TODO Show regFields.getTitle() and regFields.getInstructions() + // Create a new form without username and password that we will render ourself + DataForm extRegFields = regFields.asBuilder() + .removeField("username") + .removeField("password") + .build(); + DataFormUI dataFormUI = new DataFormUI(extRegFields); + return dataFormUI; + } + + // TODO This method should be provided by the Smack https://github.com/igniterealtime/Smack/pull/618 + private Registration getRegistrationInfo() { + Registration reg = new Registration(); + reg.setTo(connection.getXMPPServiceDomain()); + try { + return connection.createStanzaCollectorAndSend(new StanzaIdFilter(reg.getStanzaId()), reg).nextResultOrThrow(); + } catch (Exception e) { + Log.error("Unable to get registration form", e); + return null; + } + } + /** * Creates the new account using the supplied information. */ @@ -296,9 +347,10 @@ public Object construct() { return e; } try { + Map attrs = getRegistrationAttributes(); Localpart localpart = Localpart.from(getUsername()); final AccountManager accountManager = AccountManager.getInstance(connection); - accountManager.createAccount(localpart, getPassword()); + accountManager.createAccount(localpart, getPassword(), attrs); } catch (XMPPException | SmackException | InterruptedException | XmppStringprepException e) { @@ -339,6 +391,17 @@ public void finished() { worker.start(); } + private Map getRegistrationAttributes() { + Map attrs = new HashMap<>(); + if (registrationForm != null) { + List fields = registrationForm.getFilledForm().getFields(); + for (FormField f : fields) { + attrs.put(f.getFieldName(), f.getFirstValue()); + } + } + return attrs; + } + /** * Called if the account creation failed. * @@ -383,7 +446,7 @@ public void invoke(JFrame parent) { dialog.getContentPane().add(titlePanel, BorderLayout.NORTH); dialog.getContentPane().add(this, BorderLayout.CENTER); dialog.pack(); - dialog.setSize(400, 300); + dialog.setSize(400, 400); dialog.setLocationRelativeTo(parent); dialog.setVisible(true); } From aaf0eb0d5e63d9331ba5cefe5bbb260084af868e Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Wed, 28 Aug 2024 09:29:26 +0300 Subject: [PATCH 10/15] SPARK-2341 Hide instructions by default --- .../main/java/org/jivesoftware/AccountCreationWizard.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 67abbd827..9ec20af13 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -127,6 +127,8 @@ public AccountCreationWizard() { ResourceUtils.resButton(startRegistrationButton, Res.getString("button.start.registration")); startRegistrationButton.addActionListener( actionEvent -> startRegistration() ); + instructionsLabel.setVisible(false); + formPanel.setVisible(false); formPanelFields.setVisible(false); @@ -236,12 +238,15 @@ private void startRegistration() { formPanel.setVisible(true); createAccountButton.setEnabled(true); String instructions = accountManager.getAccountInstructions(); - instructionsLabel.setText(instructions); registrationForm = getRegistrationForm(); if (registrationForm != null) { formPanelFields.add(registrationForm); formPanelFields.setVisible(true); } + if (instructions != null) { + instructionsLabel.setText(instructions); + instructionsLabel.setVisible(true); + } } else { String message = Res.getString("message.create.account.not.allowed"); JOptionPane.showMessageDialog(this, message, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); From 45ea7d8c3be68b02a764687713056bfc2569045f Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Wed, 28 Aug 2024 09:30:05 +0300 Subject: [PATCH 11/15] SPARK-2341 Show instructions from registrationForm --- .../jivesoftware/AccountCreationWizard.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 9ec20af13..0c7fc8eb7 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -237,8 +237,17 @@ private void startRegistration() { if (accountManager.supportsAccountCreation()) { formPanel.setVisible(true); createAccountButton.setEnabled(true); - String instructions = accountManager.getAccountInstructions(); - registrationForm = getRegistrationForm(); + String instructions = null; + Registration info = getRegistrationInfo(); + if (info != null) { + DataForm regFields = info.getExtension(DataForm.class); + if (regFields != null) { + registrationForm = getRegistrationForm(regFields); + instructions = String.join("\n", regFields.getInstructions()); + } else { + instructions = info.getInstructions(); + } + } if (registrationForm != null) { formPanelFields.add(registrationForm); formPanelFields.setVisible(true); @@ -263,16 +272,7 @@ private void startRegistration() { } } - private DataFormUI getRegistrationForm() { - Registration info = getRegistrationInfo(); - if (info == null) { - return null; - } - DataForm regFields = info.getExtension(DataForm.class); - if (regFields == null) { - return null; - } - // TODO Show regFields.getTitle() and regFields.getInstructions() + private DataFormUI getRegistrationForm(DataForm regFields) { // Create a new form without username and password that we will render ourself DataForm extRegFields = regFields.asBuilder() .removeField("username") From 3715013a0b522f170ce5f5eda704d58a63b73fe7 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sat, 31 Aug 2024 21:59:52 +0300 Subject: [PATCH 12/15] SPARK-2341 Enable all providers and download a list --- .../java/org/jivesoftware/XmppProviders.java | 89 +++++++++++++++---- .../org/jivesoftware/XmppProvidersTest.java | 22 +++++ 2 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 core/src/test/java/org/jivesoftware/XmppProvidersTest.java diff --git a/core/src/main/java/org/jivesoftware/XmppProviders.java b/core/src/main/java/org/jivesoftware/XmppProviders.java index fb69b6717..29a17ff84 100644 --- a/core/src/main/java/org/jivesoftware/XmppProviders.java +++ b/core/src/main/java/org/jivesoftware/XmppProviders.java @@ -17,44 +17,97 @@ package org.jivesoftware; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.jivesoftware.spark.util.log.Log; + import javax.swing.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import static java.util.Arrays.asList; + public class XmppProviders { /** * Providers A - * Disabled providers that requires a CAPTCHA */ private static final String[] providers = new String[]{ -// "07f.de", -// "chalec.org", -// "chapril.org", -// "chatrix.one", -// "draugr.de", -// "hookipa.net", + "07f.de", + "chalec.org", + "chapril.org", + "chatrix.one", + "draugr.de", + "hookipa.net", "jabber.fr", -// "macaw.me", -// "magicbroccoli.de", -// "nixnet.services", -// "projectsegfau.lt", -// "redlibre.es", -// "suchat.org", -// "sure.im", -// "trashserver.net", + "macaw.me", + "magicbroccoli.de", + "nixnet.services", + "projectsegfau.lt", + "redlibre.es", + "suchat.org", + "sure.im", + "trashserver.net", "xmpp.earth", "yax.im", }; public static ComboBoxModel getXmppProvidersModel() { DefaultComboBoxModel model = new DefaultComboBoxModel<>(); - for (String provider : providers) { + List providersList = downloadProvidersList(); + if (providersList == null) { + // fallback to static list + providersList = asList(providers); + } + for (String provider : providersList) { model.addElement(provider); } // Randomly pre-select a provider - int randomProviderIdx = new Random().nextInt(providers.length); - model.setSelectedItem(providers[randomProviderIdx]); + int randomProviderIdx = new Random().nextInt(providersList.size()); + model.setSelectedItem(providersList.get(randomProviderIdx)); return model; } + + static List downloadProvidersList() { + Log.debug("Download providers"); + try (CloseableHttpClient httpClient = HttpClients.createSystem()) { + HttpGet request = new HttpGet("https://data.xmpp.net/providers/v2/providers-As.json"); + CloseableHttpResponse httpResponse = httpClient.execute(request); + final int statusCode = httpResponse.getCode(); + if (statusCode == 200) { + String json = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); + return parseProvidersJson(json); + } + Log.error("Download providers: bad status " + statusCode); + return null; + } catch (Exception e) { + Log.error("Download providers: error", e); + return null; + } + } + + static List parseProvidersJson(String json) { + // manually parse JSON array + json = json.trim(); + if (json.charAt(0) != '[' || json.charAt(json.length() - 1) != ']') { + return null; + } + String[] lines = json.substring(1, json.length() - 1).split(","); + List providers = new ArrayList<>(lines.length); + for (String line : lines) { + line = line.trim(); + if (line.charAt(0) != '"' || line.charAt(line.length() - 1) != '"') { + continue; + } + String provider = line.substring(1, line.length() - 1); + providers.add(provider); + } + return providers; + } } diff --git a/core/src/test/java/org/jivesoftware/XmppProvidersTest.java b/core/src/test/java/org/jivesoftware/XmppProvidersTest.java new file mode 100644 index 000000000..abcb867e0 --- /dev/null +++ b/core/src/test/java/org/jivesoftware/XmppProvidersTest.java @@ -0,0 +1,22 @@ +package org.jivesoftware; + +import org.junit.Test; + +import java.util.List; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class XmppProvidersTest { + + @Test + public void testParseProvidersJson() { + List providers = XmppProviders.parseProvidersJson("[\n" + + " \"07f.de\",\n" + + " \"404.city\",\n" + + " \"5222.de\"" + + "]"); + assertEquals(asList("07f.de", "404.city", "5222.de"), providers); + } + +} From b7793f6241d7712bbe78f0d2cd0a1997b2989d80 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 1 Sep 2024 15:12:53 +0300 Subject: [PATCH 13/15] XmppProviders.downloadProvidersList(): use executeOpen and close response --- .../java/org/jivesoftware/XmppProviders.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/XmppProviders.java b/core/src/main/java/org/jivesoftware/XmppProviders.java index 29a17ff84..fbe3f814c 100644 --- a/core/src/main/java/org/jivesoftware/XmppProviders.java +++ b/core/src/main/java/org/jivesoftware/XmppProviders.java @@ -19,8 +19,8 @@ import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.jivesoftware.spark.util.log.Log; @@ -78,14 +78,15 @@ static List downloadProvidersList() { Log.debug("Download providers"); try (CloseableHttpClient httpClient = HttpClients.createSystem()) { HttpGet request = new HttpGet("https://data.xmpp.net/providers/v2/providers-As.json"); - CloseableHttpResponse httpResponse = httpClient.execute(request); - final int statusCode = httpResponse.getCode(); - if (statusCode == 200) { - String json = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); - return parseProvidersJson(json); + try (ClassicHttpResponse httpResponse = httpClient.executeOpen(null, request, null)) { + final int statusCode = httpResponse.getCode(); + if (statusCode == 200) { + String json = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); + return parseProvidersJson(json); + } + Log.error("Download providers: bad status " + statusCode); + return null; } - Log.error("Download providers: bad status " + statusCode); - return null; } catch (Exception e) { Log.error("Download providers: error", e); return null; From c50697692b12756dc28898609b641a7d45dd2f92 Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 1 Sep 2024 20:44:02 +0300 Subject: [PATCH 14/15] XmppProviders.getXmppProvidersModel(): return a List --- .../jivesoftware/AccountCreationWizard.java | 9 +++++++- .../java/org/jivesoftware/XmppProviders.java | 21 ++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 0c7fc8eb7..26887fd81 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -59,6 +59,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import static org.jivesoftware.sparkimpl.certificates.SparkSSLContextCreator.Options.ONLY_SERVER_SIDE; @@ -122,7 +123,13 @@ public FormPanel() { public AccountCreationWizard() { // Associate Mnemonics serverField.setEditable(true); - serverField.setModel(XmppProviders.getXmppProvidersModel()); + List providers = XmppProviders.getXmppProvidersModel(); + for (String provider : providers) { + serverField.addItem(provider); + } + // Randomly pre-select a provider + int randomProviderIdx = new Random().nextInt(providers.size()); + serverField.setSelectedIndex(randomProviderIdx); ResourceUtils.resButton(startRegistrationButton, Res.getString("button.start.registration")); startRegistrationButton.addActionListener( actionEvent -> startRegistration() ); diff --git a/core/src/main/java/org/jivesoftware/XmppProviders.java b/core/src/main/java/org/jivesoftware/XmppProviders.java index fbe3f814c..d0c657e5f 100644 --- a/core/src/main/java/org/jivesoftware/XmppProviders.java +++ b/core/src/main/java/org/jivesoftware/XmppProviders.java @@ -24,12 +24,9 @@ import org.apache.hc.core5.http.io.entity.EntityUtils; import org.jivesoftware.spark.util.log.Log; -import javax.swing.*; - import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.Random; import static java.util.Arrays.asList; @@ -58,20 +55,14 @@ public class XmppProviders { "yax.im", }; - public static ComboBoxModel getXmppProvidersModel() { - DefaultComboBoxModel model = new DefaultComboBoxModel<>(); + public static List getXmppProvidersModel() { List providersList = downloadProvidersList(); - if (providersList == null) { - // fallback to static list - providersList = asList(providers); - } - for (String provider : providersList) { - model.addElement(provider); + if (providersList != null) { + return providersList; } - // Randomly pre-select a provider - int randomProviderIdx = new Random().nextInt(providersList.size()); - model.setSelectedItem(providersList.get(randomProviderIdx)); - return model; + // fallback to static list + providersList = asList(providers); + return providersList; } static List downloadProvidersList() { From c91fb004e7327fbb41986743027c67bd23a3abdf Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 1 Sep 2024 21:24:20 +0300 Subject: [PATCH 15/15] SPARK-2341 Show CAPTCHA image --- .../jivesoftware/AccountCreationWizard.java | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 26887fd81..cd0b2e71d 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -26,6 +26,7 @@ import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.jivesoftware.smack.util.DNSUtil; +import org.jivesoftware.smackx.bob.element.BoBDataExtension; import org.jivesoftware.smackx.iqregister.AccountManager; import org.jivesoftware.smackx.iqregister.packet.Registration; import org.jivesoftware.smackx.xdata.FormField; @@ -79,6 +80,8 @@ public class AccountCreationWizard extends JPanel { private final JPanel formPanelFields = new JPanel(); + private final JLabel captcha = new JLabel(); + private final JButton createAccountButton = new JButton(); private JDialog dialog; @@ -139,6 +142,11 @@ public AccountCreationWizard() { formPanel.setVisible(false); formPanelFields.setVisible(false); + captcha.setPreferredSize(new java.awt.Dimension(250, 80)); + captcha.setRequestFocusEnabled(false); + captcha.setHorizontalAlignment(SwingConstants.CENTER); + instructionsLabel.setVisible(false); + JLabel serverLabel = new JLabel(); ResourceUtils.resLabel( serverLabel, serverField, Res.getString("label.server") + ":"); ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account")); @@ -165,10 +173,12 @@ public AccountCreationWizard() { add(formPanelFields, new GridBagConstraints(0, 4, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); + add(captcha, new GridBagConstraints(0, 5, 4, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); + add(progressBar, new GridBagConstraints(1, 6, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); - add(createAccountButton, new GridBagConstraints(2, 6, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); - add( closeButton, new GridBagConstraints(3, 6, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add(createAccountButton, new GridBagConstraints(2, 7, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); + add( closeButton, new GridBagConstraints(3, 7, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); } /** @@ -245,11 +255,19 @@ private void startRegistration() { formPanel.setVisible(true); createAccountButton.setEnabled(true); String instructions = null; + Icon captchaIcon = null; Registration info = getRegistrationInfo(); if (info != null) { + // try to get the CAPTCHA image from + // BASE64_OF_PNG_HERE + BoBDataExtension captchaBob = info.getExtension(BoBDataExtension.class); + if (captchaBob != null && "image/png".equals(captchaBob.getBobData().getType())) { + byte[] imageData = captchaBob.getBobData().getContent(); + captchaIcon = new ImageIcon(imageData); + } DataForm regFields = info.getExtension(DataForm.class); if (regFields != null) { - registrationForm = getRegistrationForm(regFields); + registrationForm = getRegistrationForm(regFields, captchaIcon != null); instructions = String.join("\n", regFields.getInstructions()); } else { instructions = info.getInstructions(); @@ -263,6 +281,10 @@ private void startRegistration() { instructionsLabel.setText(instructions); instructionsLabel.setVisible(true); } + if (captchaIcon != null) { + captcha.setIcon(captchaIcon); + instructionsLabel.setVisible(true); + } } else { String message = Res.getString("message.create.account.not.allowed"); JOptionPane.showMessageDialog(this, message, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE); @@ -279,13 +301,16 @@ private void startRegistration() { } } - private DataFormUI getRegistrationForm(DataForm regFields) { - // Create a new form without username and password that we will render ourself - DataForm extRegFields = regFields.asBuilder() + private DataFormUI getRegistrationForm(DataForm regFields, boolean noCaptcha) { + // Create a new form without username and password that we will render ourselves + DataForm.Builder extRegFields = regFields.asBuilder() .removeField("username") - .removeField("password") - .build(); - DataFormUI dataFormUI = new DataFormUI(extRegFields); + .removeField("password"); + if (noCaptcha) { + extRegFields.removeField("captcha-fallback-url"); + extRegFields.removeField("captcha-fallback-text"); + } + DataFormUI dataFormUI = new DataFormUI(extRegFields.build()); return dataFormUI; } @@ -458,7 +483,7 @@ public void invoke(JFrame parent) { dialog.getContentPane().add(titlePanel, BorderLayout.NORTH); dialog.getContentPane().add(this, BorderLayout.CENTER); dialog.pack(); - dialog.setSize(400, 400); + dialog.setSize(400, 580); dialog.setLocationRelativeTo(parent); dialog.setVisible(true); }