From 7f57900d9f5f7286a4eec77406e4162d49d2f8b5 Mon Sep 17 00:00:00 2001 From: Steven Tracey Date: Thu, 24 Feb 2022 23:04:58 -0500 Subject: [PATCH] Successfully create and load profiles, added functional gui --- LauncherExe/LauncherExe.iml | 5 +- LauncherExe/src/main.rs | 5 +- src/main/java/tech/nevets/jaml/Config.java | 1 + src/main/java/tech/nevets/jaml/DiscordRP.java | 2 +- src/main/java/tech/nevets/jaml/JAML.java | 29 ++-- src/main/java/tech/nevets/jaml/Profile.java | 28 +++- src/main/java/tech/nevets/jaml/Profiles.java | 16 +-- .../java/tech/nevets/jaml/gui/GuiHandler.java | 17 +++ .../jaml/gui/{GUI.java => HomeGui.java} | 29 ++-- .../tech/nevets/jaml/gui/NewProfileGui.java | 131 ++++++++++++++++++ .../java/tech/nevets/jaml/util/Encryptor.java | 80 +++++++++++ .../tech/nevets/jaml/util/MultiReturn.java | 31 +++++ 12 files changed, 315 insertions(+), 59 deletions(-) create mode 100644 src/main/java/tech/nevets/jaml/gui/GuiHandler.java rename src/main/java/tech/nevets/jaml/gui/{GUI.java => HomeGui.java} (63%) create mode 100644 src/main/java/tech/nevets/jaml/gui/NewProfileGui.java create mode 100644 src/main/java/tech/nevets/jaml/util/Encryptor.java create mode 100644 src/main/java/tech/nevets/jaml/util/MultiReturn.java diff --git a/LauncherExe/LauncherExe.iml b/LauncherExe/LauncherExe.iml index 183c2ef..6b25966 100644 --- a/LauncherExe/LauncherExe.iml +++ b/LauncherExe/LauncherExe.iml @@ -2,7 +2,10 @@ - + + + + \ No newline at end of file diff --git a/LauncherExe/src/main.rs b/LauncherExe/src/main.rs index 32bd633..909c04c 100644 --- a/LauncherExe/src/main.rs +++ b/LauncherExe/src/main.rs @@ -4,13 +4,10 @@ fn main() { let mut cmd = Command::new("java"); cmd.arg("-jar"); - cmd.arg("JAML.jar"); + cmd.arg("JAML.jar"); match cmd.output() { Ok(output) => { - unsafe { - println!("Output: {}", String::from_utf8_unchecked(output.stdout)); - } }, Err(e) => { println!("{}", e); diff --git a/src/main/java/tech/nevets/jaml/Config.java b/src/main/java/tech/nevets/jaml/Config.java index 43f0960..a62763a 100644 --- a/src/main/java/tech/nevets/jaml/Config.java +++ b/src/main/java/tech/nevets/jaml/Config.java @@ -26,6 +26,7 @@ public class Config { ymlFile.addDefault("java.jdk8", ""); ymlFile.addDefault("java.jdk16", ""); ymlFile.addDefault("java.jdk17", ""); + ymlFile.addDefault("launcher.default-profile", "default"); ymlFile.addDefault("launcher.path","default"); ymlFile.setComment("launcher.path","Path to JAML files\n" + "default: " + JAML.path.toString()); ymlFile.addDefault("launcher.verbose", false); diff --git a/src/main/java/tech/nevets/jaml/DiscordRP.java b/src/main/java/tech/nevets/jaml/DiscordRP.java index 0aa15d4..22ff0ba 100644 --- a/src/main/java/tech/nevets/jaml/DiscordRP.java +++ b/src/main/java/tech/nevets/jaml/DiscordRP.java @@ -19,7 +19,7 @@ public class DiscordRP { }).build(); DiscordRPC.discordInitialize("942986640043941938", handlers, true); - //DiscordRPC.discordRegister("942986640043941938", ""); + DiscordRPC.discordRegister("942986640043941938", ""); new Thread(() -> { while (running) { diff --git a/src/main/java/tech/nevets/jaml/JAML.java b/src/main/java/tech/nevets/jaml/JAML.java index d72e84b..793b820 100644 --- a/src/main/java/tech/nevets/jaml/JAML.java +++ b/src/main/java/tech/nevets/jaml/JAML.java @@ -1,7 +1,7 @@ package tech.nevets.jaml; import org.simpleyaml.configuration.file.YamlFile; -import tech.nevets.jaml.gui.GUI; +import tech.nevets.jaml.gui.GuiHandler; import java.io.IOException; import java.nio.file.Path; @@ -10,28 +10,25 @@ public class JAML { public static YamlFile config; public static Path path; public static DiscordRP drp = new DiscordRP(); + public static GuiHandler guiHandler; + public static Profile activeProfile; - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) { makeDirs(); Config.loadConfig(); config = Config.getConfig(); try { - Profiles.loadProfile("test"); + Profiles pfs = new Profiles(); + activeProfile = pfs.loadProfile(config.getString("launcher.default-profile")); } catch (IOException e) { - e.printStackTrace(); + System.out.println("Unable to load default profile: " + e.getMessage()); } -// try { -// Profiles.createProfile("testing"); -// } catch (IOException e) { -// e.printStackTrace(); -// } - drp.start(); - GUI.startGui(); + guiHandler = new GuiHandler(); drp.shutdown(); } @@ -73,14 +70,4 @@ public class JAML { e.printStackTrace(); } } - -// public static void initDiscord() { -// DiscordEventHandlers handlers = new DiscordEventHandlers.Builder().setReadyEventHandler((user) -> { -// System.out.println("Welcome " + user.username + "#" + user.discriminator + "."); -// DiscordRichPresence.Builder presence = new DiscordRichPresence.Builder(""); -// DiscordRPC.discordUpdatePresence(presence.build()); -// }).build(); -// DiscordRPC.discordInitialize("942986640043941938", handlers, false); -// DiscordRPC.discordRegister("942986640043941938", ""); -// } } \ No newline at end of file diff --git a/src/main/java/tech/nevets/jaml/Profile.java b/src/main/java/tech/nevets/jaml/Profile.java index 0a47d41..26fad9f 100644 --- a/src/main/java/tech/nevets/jaml/Profile.java +++ b/src/main/java/tech/nevets/jaml/Profile.java @@ -6,7 +6,9 @@ public class Profile { private String profileName; private String email; private String hashedPassword; - private Path gamePath; + private String key; + private String salt; + private String gamePath; private String version; private String loader; private Boolean offlineMode; @@ -19,7 +21,7 @@ public class Profile { } public void setProfileName(String profileName) { - this.profileName = profileName; + this.profileName = profileName.toLowerCase(); } public String getEmail() { @@ -38,12 +40,28 @@ public class Profile { this.hashedPassword = hashedPassword; } + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getSalt() { + return salt; + } + + public void setSalt(String salt) { + this.salt = salt; + } + public Path getGamePath() { - return gamePath; + return Path.of(gamePath); } public void setGamePath(Path gamePath) { - this.gamePath = gamePath; + this.gamePath = String.valueOf(gamePath); } public String getVersion() { @@ -71,6 +89,6 @@ public class Profile { } public String toString() { - return "Profile [ profileName: " + profileName + ", email: " + email + ", hashedPassword: " + hashedPassword + ", gamePath: " + gamePath + ", version: " + version + ", loader: " + loader + ", offlineMode: " + offlineMode + " ]"; + return "{ profileName: " + profileName + ", email: " + email + ", hashedPassword: " + hashedPassword + ", key: " + key + ", salt: " + salt + ", gamePath: " + gamePath + ", version: " + version + ", loader: " + loader + ", offlineMode: " + offlineMode + " }"; } } diff --git a/src/main/java/tech/nevets/jaml/Profiles.java b/src/main/java/tech/nevets/jaml/Profiles.java index c522af3..88ba0e3 100644 --- a/src/main/java/tech/nevets/jaml/Profiles.java +++ b/src/main/java/tech/nevets/jaml/Profiles.java @@ -8,26 +8,22 @@ import java.nio.file.Path; public class Profiles { private static final Path profilePath = Path.of(JAML.path + "\\profiles\\"); - public static void createProfile(String profileName) throws IOException { + public static void createProfile(Profile profile) throws IOException { + String profileName = profile.getProfileName(); Writer writer = new FileWriter(profilePath + "\\" + profileName + ".json"); - String jsonString = "{}"; GsonBuilder builder = new GsonBuilder(); builder.setPrettyPrinting(); - Gson gson = builder.create(); - Profile profile = gson.fromJson(jsonString, Profile.class); - System.out.println(profile); - - jsonString = gson.toJson(profile); - System.out.println(jsonString); + String jsonString = gson.toJson(profile); writer.write(jsonString); + writer.close(); } - public static void loadProfile(String profileName) throws FileNotFoundException { + public Profile loadProfile(String profileName) throws FileNotFoundException { BufferedReader reader = new BufferedReader(new FileReader(profilePath + "\\" + profileName + ".json")); Profile profile = new Gson().fromJson(reader, Profile.class); - System.out.println(profile.getProfileName()); + return profile; } } diff --git a/src/main/java/tech/nevets/jaml/gui/GuiHandler.java b/src/main/java/tech/nevets/jaml/gui/GuiHandler.java new file mode 100644 index 0000000..c4a69a6 --- /dev/null +++ b/src/main/java/tech/nevets/jaml/gui/GuiHandler.java @@ -0,0 +1,17 @@ +package tech.nevets.jaml.gui; + +public class GuiHandler { + + public GuiHandler() { + HomeGui homeGui = new HomeGui(); + Thread homeGuiThread = new Thread(homeGui); + homeGuiThread.start(); + } + + public void startNewProfileGui() { + NewProfileGui newProfileGui = new NewProfileGui(); + Thread newProfileGuiThread = new Thread(newProfileGui); + newProfileGuiThread.start(); + } + +} diff --git a/src/main/java/tech/nevets/jaml/gui/GUI.java b/src/main/java/tech/nevets/jaml/gui/HomeGui.java similarity index 63% rename from src/main/java/tech/nevets/jaml/gui/GUI.java rename to src/main/java/tech/nevets/jaml/gui/HomeGui.java index 8e9bb84..2c6a073 100644 --- a/src/main/java/tech/nevets/jaml/gui/GUI.java +++ b/src/main/java/tech/nevets/jaml/gui/HomeGui.java @@ -1,33 +1,28 @@ package tech.nevets.jaml.gui; import tech.nevets.jaml.JAML; + import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class GUI implements ActionListener { - //TODO Add important things on instead of POC +public class HomeGui implements Runnable, ActionListener { - private int count = 0; - JFrame frame; - JPanel panel; - JButton button; - JLabel label; + private JFrame frame; + private JPanel panel; - public GUI() { + public void startGui() { frame = new JFrame(); - button = new JButton("Click me!"); + JButton button = new JButton("Create New Profile"); button.addActionListener(this); - label = new JLabel("Number of Clicks: 0"); - panel = new JPanel(); panel.setBorder(BorderFactory.createEmptyBorder(300, 300, 100, 300)); panel.setLayout(new GridLayout(0, 1)); + panel.add(button); - panel.add(label); frame.add(panel, BorderLayout.CENTER); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -37,13 +32,13 @@ public class GUI implements ActionListener { frame.setVisible(true); } - public static void startGui() { - new GUI(); + @Override + public void actionPerformed(ActionEvent e) { + JAML.guiHandler.startNewProfileGui(); } @Override - public void actionPerformed(ActionEvent e) { - count++; - label.setText("Number of Clicks: " + count); + public void run() { + startGui(); } } diff --git a/src/main/java/tech/nevets/jaml/gui/NewProfileGui.java b/src/main/java/tech/nevets/jaml/gui/NewProfileGui.java new file mode 100644 index 0000000..21e8820 --- /dev/null +++ b/src/main/java/tech/nevets/jaml/gui/NewProfileGui.java @@ -0,0 +1,131 @@ +package tech.nevets.jaml.gui; + +import tech.nevets.jaml.JAML; +import tech.nevets.jaml.Profile; +import tech.nevets.jaml.Profiles; +import tech.nevets.jaml.util.Encryptor; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.nio.file.Path; + +public class NewProfileGui implements Runnable, ActionListener { + //TODO Formatting + private JFrame frame; + private JPanel panel; + + private JTextField profileNameField; + private JTextField emailField; + private JPasswordField passwordField; + private JTextField gamePathField; + private JTextField versionField; + private JTextField loaderField; + private JTextField offlineModeField; + + public void startGui() { + frame = new JFrame("New Profile"); + + JLabel profileNameLabel = new JLabel("Profile Name:"); + profileNameLabel.setBounds(10, 20, 80, 25); + profileNameField = new JTextField(20); + + JLabel emailLabel = new JLabel("Email:"); + emailLabel.setBounds(10, 50, 80, 25); + emailField = new JTextField(20); + + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setBounds(100, 50, 165, 25); + passwordField = new JPasswordField(20); + + JLabel gamePathLabel = new JLabel("Game Path:"); + gamePathLabel.setBounds(10, 80, 80, 25); + gamePathField = new JTextField(20); + + JButton gamePathButton = new JButton("Choose Path"); + gamePathButton.setBounds(200, 80, 25, 25); + gamePathButton.addActionListener(ae -> { + JFileChooser fileChooser = new JFileChooser(JAML.path.toString()); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fileChooser.showSaveDialog(null); + if (fileChooser.getSelectedFile() == null) { return; } + gamePathField.setText(fileChooser.getSelectedFile().toString()); + fileChooser.setVisible(false); + }); + + JLabel versionLabel = new JLabel("Version:"); + versionLabel.setBounds(100, 80, 165, 25); + versionField = new JTextField(20); + + JLabel loaderLabel = new JLabel("Loader:"); + loaderLabel.setBounds(10, 110, 80, 25); + loaderField = new JTextField(20); + + JLabel offlineModeLabel = new JLabel("Offline Mode:"); + offlineModeLabel.setBounds(100, 110, 165, 25); + offlineModeField = new JTextField(20); + + JButton button = new JButton("Create Profile"); + button.addActionListener(this); + + panel = new JPanel(); + panel.setBorder(BorderFactory.createEmptyBorder(300, 300, 100, 300)); + panel.setLayout(new GridLayout(0, 1)); + panel.add(profileNameLabel); + panel.add(profileNameField); + panel.add(emailLabel); + panel.add(emailField); + panel.add(passwordLabel); + panel.add(passwordField); + panel.add(gamePathLabel); + panel.add(gamePathField); + panel.add(gamePathButton); + panel.add(versionLabel); + panel.add(versionField); + panel.add(loaderLabel); + panel.add(loaderField); + panel.add(offlineModeLabel); + panel.add(offlineModeField); + panel.add(button); + + frame.add(panel, BorderLayout.CENTER); + frame.setSize(500, 500); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setTitle("JAML"); + frame.setIconImage(new ImageIcon(JAML.path + "\\assets\\icon.png").getImage()); + frame.pack(); + frame.setVisible(true); + } + + @Override + public void actionPerformed(ActionEvent ae) { + Profile profile = new Profile(); + profile.setProfileName(profileNameField.getText()); + profile.setEmail(emailField.getText()); + + if (passwordField.getPassword().length > 0){ + profile.setHashedPassword(Encryptor.encrypt(String.valueOf(passwordField.getPassword())).getData()); + profile.setKey(Encryptor.encrypt(String.valueOf(passwordField.getPassword())).getKey()); + profile.setSalt(Encryptor.encrypt(String.valueOf(passwordField.getPassword())).getSalt()); + } + + profile.setGamePath(Path.of(gamePathField.getText())); + profile.setVersion(versionField.getText()); + profile.setLoader(loaderField.getText()); + profile.setOfflineMode(Boolean.parseBoolean(offlineModeField.getText())); + try { + Profiles.createProfile(profile); + } catch (IOException e) { + e.printStackTrace(); + } + + frame.dispose(); + } + + @Override + public void run() { + startGui(); + } +} diff --git a/src/main/java/tech/nevets/jaml/util/Encryptor.java b/src/main/java/tech/nevets/jaml/util/Encryptor.java new file mode 100644 index 0000000..7141427 --- /dev/null +++ b/src/main/java/tech/nevets/jaml/util/Encryptor.java @@ -0,0 +1,80 @@ +package tech.nevets.jaml.util; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.spec.KeySpec; +import java.util.Base64; +import java.util.Random; + +public class Encryptor { + + public static MultiReturn encrypt(String textToEncrypt) { + String key = generateHash(); + String salt = generateHash(); + String hashedData = null; + + try { + byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + IvParameterSpec ivspec = new IvParameterSpec(iv); + + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + KeySpec spec = new PBEKeySpec(key.toCharArray(), salt.getBytes(), 65536, 256); + SecretKey tmp = factory.generateSecret(spec); + SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec); + hashedData = Base64.getEncoder().encodeToString(cipher.doFinal(textToEncrypt.getBytes(StandardCharsets.UTF_8))); + + } catch (Exception e) { + System.out.println("Error while encrypting: " + e.getMessage()); + } + + MultiReturn pair = new MultiReturn(hashedData, key, salt); + + return pair; + } + + public static String decrypt(MultiReturn pair) { + String hash = pair.getData(); + String key = pair.getKey(); + String salt = pair.getSalt(); + String password = null; + + try { + byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + IvParameterSpec ivspec = new IvParameterSpec(iv); + + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + KeySpec spec = new PBEKeySpec(key.toCharArray(), salt.getBytes(), 65536, 256); + SecretKey tmp = factory.generateSecret(spec); + SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec); + password = new String(cipher.doFinal(Base64.getDecoder().decode(hash))); + + } catch (Exception e) { + System.out.println("Error while decrypting: " + e.getMessage()); + } + + return password; + } + + public static String generateHash(){ + String[] chars = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "!", "@", "#", "$", "%", "&"}; + Random rand = new Random(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < 64; i++) { + sb.append(chars[rand.nextInt(chars.length)]); + } + + return sb.toString(); + } +} diff --git a/src/main/java/tech/nevets/jaml/util/MultiReturn.java b/src/main/java/tech/nevets/jaml/util/MultiReturn.java new file mode 100644 index 0000000..f07b466 --- /dev/null +++ b/src/main/java/tech/nevets/jaml/util/MultiReturn.java @@ -0,0 +1,31 @@ +package tech.nevets.jaml.util; + +public class MultiReturn { + + private String data; + private String key; + private String salt; + + public MultiReturn(String data, String key) { + this.data = data; + this.key = key; + } + + public MultiReturn(String data, String key, String salt) { + this.data = data; + this.key = key; + this.salt = salt; + } + + public String getData() { + return data; + } + + public String getKey() { + return key; + } + + public String getSalt() { + return salt; + } +}