diff --git a/.gitattributes b/.gitattributes index 3168d97ff22..9f814af0113 100644 --- a/.gitattributes +++ b/.gitattributes @@ -916,6 +916,7 @@ forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletCont forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletLoad.java -text forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletQuick.java -text forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java -text +forge-gui-desktop/src/main/java/forge/screens/home/online/LoginDialog.java -text forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java -text forge-gui-desktop/src/main/java/forge/screens/home/package-info.java -text forge-gui-desktop/src/main/java/forge/screens/home/quest/CSubmenuChallenges.java -text @@ -17212,4 +17213,7 @@ forge-net/src/main/java/forge/net/protocol/toserver/EchoPacketSrv.java -text forge-net/src/main/java/forge/net/protocol/toserver/IPacketSrv.java -text forge-net/src/main/java/forge/net/protocol/toserver/IncorrectPacketSrv.java -text forge-net/src/main/java/forge/net/protocol/toserver/package-info.java -text +forge-net/src/main/java/forge/server/ServerUtil.java -text +forge-net/src/main/php/login.php -text +forge-net/src/main/php/logout.php -text /pom.xml svneol=native#text/xml diff --git a/forge-core/src/main/java/forge/util/Base64Coder.java b/forge-core/src/main/java/forge/util/Base64Coder.java index e641ffef940..2c88603dedc 100644 --- a/forge-core/src/main/java/forge/util/Base64Coder.java +++ b/forge-core/src/main/java/forge/util/Base64Coder.java @@ -31,6 +31,12 @@ package forge.util; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + /** * A Base64 encoder/decoder. *

@@ -360,6 +366,28 @@ public final class Base64Coder { return out; } + private static final char[] PASSWORD = "enfldsgbnlsngdlksdsgm".toCharArray(); + private static final byte[] SALT = { + (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12, + (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12, + }; + + public static String encrypt(String value) throws Exception { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); + pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20)); + return String.valueOf(encode(pbeCipher.doFinal(value.getBytes("UTF-8")))); + } + + public static String decrypt(String value) throws Exception { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); + pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20)); + return new String(pbeCipher.doFinal(decode(value)), "UTF-8"); + } + // Dummy constructor. /** *

@@ -368,5 +396,4 @@ public final class Base64Coder { */ private Base64Coder() { } - } // end class Base64Coder diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java index 8c0156ae4c7..82389e2eb02 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java @@ -22,7 +22,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - + LoginDialog.login(); } }); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/LoginDialog.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/LoginDialog.java new file mode 100644 index 00000000000..2071ce47b93 --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/LoginDialog.java @@ -0,0 +1,120 @@ +package forge.screens.home.online; + +import java.awt.Dimension; + +import javax.swing.JPanel; + +import net.miginfocom.swing.MigLayout; +import forge.UiCommand; +import forge.error.BugReporter; +import forge.model.FModel; +import forge.properties.ForgePreferences.FPref; +import forge.server.ServerUtil; +import forge.toolbox.FButton; +import forge.toolbox.FCheckBox; +import forge.toolbox.FLabel; +import forge.toolbox.FOptionPane; +import forge.toolbox.FPasswordField; +import forge.toolbox.FTextField; +import forge.view.FDialog; + +@SuppressWarnings("serial") +public class LoginDialog extends FDialog { + private final FLabel lblUsername = new FLabel.Builder().text("Username:").build(); + private final FTextField txtUsername = new FTextField.Builder().build(); + private final FLabel lblPassword = new FLabel.Builder().text("Password:").build(); + private final FPasswordField txtPassword = new FPasswordField(); + private final FCheckBox cbRememberMe = new FCheckBox("Remember Me"); + private final FButton btnLogin = new FButton("Login"); + private final FButton btnCancel = new FButton("Cancel"); + + public static boolean login() { + String username = FModel.getPreferences().getPref(FPref.ONLINE_USERNAME); + String password = FModel.getPreferences().getPref(FPref.ONLINE_PASSWORD); + if (!username.isEmpty() && !password.isEmpty()) { + try { + if (ServerUtil.login(username, password)) { + return true; //avoid showing dialog if able to login with saved username/password + } + } + catch (Exception e) { + e.printStackTrace(); + } + FModel.getPreferences().setPref(FPref.ONLINE_PASSWORD, ""); //clear password if login failed + FModel.getPreferences().save(); + } + + LoginDialog dialog = new LoginDialog(username); + dialog.setVisible(true); + dialog.dispose(); + return dialog.result; + } + + private boolean result = false; + + private LoginDialog(String username) { + setTitle("Login"); + + txtUsername.setText(username); + + btnLogin.setCommand(new UiCommand() { + @Override + public void run() { + String username = txtUsername.getText(); + if (username.isEmpty()) { + FOptionPane.showErrorDialog("You must enter a username", "Login Failed"); + txtUsername.requestFocusInWindow(); + return; + } + char[] password = txtPassword.getPassword(); + if (password == null || password.length == 0) { + FOptionPane.showErrorDialog("You must enter a password", "Login Failed"); + txtPassword.requestFocusInWindow(); + return; + } + try { + String passwordStr = String.valueOf(password); + if (ServerUtil.login(username, passwordStr)) { + FModel.getPreferences().setPref(FPref.ONLINE_USERNAME, username); + FModel.getPreferences().setPref(FPref.ONLINE_PASSWORD, cbRememberMe.isSelected() ? passwordStr : ""); + FModel.getPreferences().save(); + setVisible(false); + return; + } + FOptionPane.showErrorDialog("Could not login with entered username and password.", "Login Failed"); + txtUsername.requestFocusInWindow(); + } + catch (Exception e) { + BugReporter.reportException(e, "Login Failed"); + } + } + }); + btnCancel.setCommand(new UiCommand() { + @Override + public void run() { + setVisible(false); + } + }); + + final int width = 330; + final int height = 180; + setPreferredSize(new Dimension(width, height)); + setSize(width, height); + + JPanel pnlContent = new JPanel(new MigLayout("gap 6, insets 0")); + pnlContent.setOpaque(false); + pnlContent.add(lblUsername); + pnlContent.add(txtUsername, "growx, pushx, wrap"); + pnlContent.add(lblPassword); + pnlContent.add(txtPassword, "growx, pushx, wrap"); + + add(pnlContent, "pushx, growx, wrap, span 2"); + add(cbRememberMe, "pushx, growx, wrap"); + add(btnLogin, "w 150px!, h 30px!, gapright 6px"); + add(btnCancel, "w 150px!, h 30px!"); + + if (!username.isEmpty()) { + setDefaultFocus(txtPassword); + } + } +} diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java index 355a52c0d95..2bfddda1f82 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/VSubmenuOnlineLobby.java @@ -26,11 +26,12 @@ public enum VSubmenuOnlineLobby implements IVSubmenu { private final StartButton btnStart = new StartButton(); private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); - private final JPanel constructedFrame = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); // Main content frame + private final JPanel frame = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); // Main content frame private VSubmenuOnlineLobby() { lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - constructedFrame.setOpaque(false); + + frame.setOpaque(false); pnlStart.setOpaque(false); pnlStart.add(btnStart, "align center"); } @@ -43,7 +44,7 @@ public enum VSubmenuOnlineLobby implements IVSubmenu { container.setLayout(new MigLayout("insets 0, gap 0, wrap 1, ax right")); container.add(lblTitle, "w 80%, h 40px!, gap 0 0 15px 15px, span 2, al right, pushx"); - VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(constructedFrame, "gap 20px 20px 20px 0px, push, grow"); + VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(frame, "gap 20px 20px 20px 0px, push, grow"); VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "gap 0 0 3.5%! 3.5%!, ax center"); if (container.isShowing()) { diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 4fbb0a8b66c..88360aeaf56 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -25,6 +25,8 @@ public class ForgePreferences extends PreferencesStore { * Preference identifiers, and their default values. */ public static enum FPref { + ONLINE_USERNAME(""), + ONLINE_PASSWORD(""), PLAYER_NAME (""), CONSTRUCTED_P1_DECK_STATE(""), CONSTRUCTED_P2_DECK_STATE(""), diff --git a/forge-net/.classpath b/forge-net/.classpath index 51baab63605..9fb713cac61 100644 --- a/forge-net/.classpath +++ b/forge-net/.classpath @@ -2,8 +2,9 @@ + - \ No newline at end of file + diff --git a/forge-net/src/main/java/forge/net/NetServer.java b/forge-net/src/main/java/forge/net/NetServer.java index 3e1f5764a75..09dfe15fdc5 100644 --- a/forge-net/src/main/java/forge/net/NetServer.java +++ b/forge-net/src/main/java/forge/net/NetServer.java @@ -22,14 +22,14 @@ public class NetServer { private final Server srv = new Server(); private final Set _openSockets = new CopyOnWriteArraySet(); - public int portNumber; + private int portNumber; public final int getPortNumber() { return portNumber; } public NetServer() { - SelectChannelConnector connector= new SelectChannelConnector(); + SelectChannelConnector connector = new SelectChannelConnector(); connector.setMaxIdleTime(1200000); // 20 minutes srv.addConnector(connector); diff --git a/forge-net/src/main/java/forge/server/ServerUtil.java b/forge-net/src/main/java/forge/server/ServerUtil.java new file mode 100644 index 00000000000..390be5a0763 --- /dev/null +++ b/forge-net/src/main/java/forge/server/ServerUtil.java @@ -0,0 +1,72 @@ +package forge.server; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.Inet4Address; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; + +public class ServerUtil { + public static final int PORT = 51764; //FRGE encoded on 0-25 number scale + public static final String SERVER_DIR = "http://cardforge.org/server/"; + + static { + /*try { + Context context = new InitialContext(); + DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/myDB"); + } + catch (SQLException e) { + e.printStackTrace(); + }*/ + } + + public static boolean login(String username, String password) throws Exception { + String ip = Inet4Address.getLocalHost().getHostAddress(); + String result = post("login.php", + new Argument("username", username), + new Argument("password", password), + new Argument("ip", ip)); + return false; + } + + private static class Argument { + private final String name; + private final String value; + + public Argument(String name0, String value0) { + name = name0; + value = value0; + } + } + + private static String post(String filename, Argument... args) throws Exception { + //build data to send to server + StringBuilder data = new StringBuilder(); + for (Argument arg : args) { + if (data.length() > 0) { + data.append("&"); + } + data.append(URLEncoder.encode(arg.name, "UTF-8") + "=" + + URLEncoder.encode(arg.value, "UTF-8")); + } + + //send data to server + URL url = new URL("http://myphpmysqlweb.hostei.com/" + filename); + URLConnection conn = url.openConnection(); + conn.setDoOutput(true); + OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); + wr.write(data.toString()); + wr.flush(); + + //read server response + String line; + StringBuilder sb = new StringBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + while((line = reader.readLine()) != null) { + sb.append(line); + } + return sb.toString(); + } +} diff --git a/forge-net/src/main/php/login.php b/forge-net/src/main/php/login.php new file mode 100644 index 00000000000..c43dbaf169f --- /dev/null +++ b/forge-net/src/main/php/login.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/forge-net/src/main/php/logout.php b/forge-net/src/main/php/logout.php new file mode 100644 index 00000000000..c43dbaf169f --- /dev/null +++ b/forge-net/src/main/php/logout.php @@ -0,0 +1,17 @@ + \ No newline at end of file