From d6d0ba9bd4b866c5a22c3cb89354d21c9a6a1e1f Mon Sep 17 00:00:00 2001 From: skylarmt Date: Fri, 2 Jan 2015 16:48:21 -0700 Subject: [PATCH] Add online licensing system, web calls now use https --- src/net/apocalypselabs/symat/FirstRun.form | 165 +++++++++ src/net/apocalypselabs/symat/FirstRun.java | 399 +++++++++++++++++++++ src/net/apocalypselabs/symat/MainGUI.java | 58 ++- 3 files changed, 614 insertions(+), 8 deletions(-) create mode 100644 src/net/apocalypselabs/symat/FirstRun.form create mode 100644 src/net/apocalypselabs/symat/FirstRun.java diff --git a/src/net/apocalypselabs/symat/FirstRun.form b/src/net/apocalypselabs/symat/FirstRun.form new file mode 100644 index 0000000..2eafc2c --- /dev/null +++ b/src/net/apocalypselabs/symat/FirstRun.form @@ -0,0 +1,165 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/net/apocalypselabs/symat/FirstRun.java b/src/net/apocalypselabs/symat/FirstRun.java new file mode 100644 index 0000000..83dae05 --- /dev/null +++ b/src/net/apocalypselabs/symat/FirstRun.java @@ -0,0 +1,399 @@ +/* + * Apocalypse Laboratories + * Open Source License + * + * Source code can be used for any purpose, as long as: + * - Compiled binaries are rebranded and trademarks are not + * visible by the end user at any time, except to give + * credit to Apocalypse Laboratories, such as by showing + * "Based on by Apocalypse Laboratories" or a + * similar notice; + * - You do not use the code for evil; + * - Rebranded compiled applications have significant + * differences in functionality; + * - and you provide your modified source code for download, + * under the terms of the GNU LGPL v3 or a comparable + * license. + * + * Compiled binaries cannot be redistributed or mirrored, + * unless: + * - You have written permission from Apocalypse Laboratories; + * - Downloads are not available from Apocalypse Laboratories, + * not even behind a paywall or other blocking mechanism; + * - or you have received a multi-computer license, in which + * case you should take measures to prevent unauthorized + * downloads, such as preventing download access from the + * Internet. + */ +package net.apocalypselabs.symat; + +import java.awt.Desktop; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import javax.swing.JOptionPane; +import static net.apocalypselabs.symat.MainGUI.API_URL; + +/** + * + * @author Skylar + */ +public class FirstRun extends javax.swing.JInternalFrame { + + /** + * Creates new form FirstRun + */ + public FirstRun() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + grp1 = new javax.swing.ButtonGroup(); + jLabel1 = new javax.swing.JLabel(); + singLicSel = new javax.swing.JRadioButton(); + orgLicSel = new javax.swing.JRadioButton(); + noLicSel = new javax.swing.JRadioButton(); + emailBox = new javax.swing.JTextField(); + emailLbl = new javax.swing.JLabel(); + contBtn = new javax.swing.JButton(); + exitBtn = new javax.swing.JButton(); + + setTitle("Welcome"); + setFrameIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icon16.png"))); // NOI18N + setMaximumSize(new java.awt.Dimension(435, 350)); + setMinimumSize(new java.awt.Dimension(435, 350)); + setPreferredSize(new java.awt.Dimension(435, 350)); + + jLabel1.setText("\n

Welcome to SyMAT!

\n

It would be a good idea to get this copy fully activated\n
before you go any further.

\n
\n

Do you have a license?

"); + + grp1.add(singLicSel); + singLicSel.setText("Yes, I have a single-user license"); + singLicSel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + singLicSelActionPerformed(evt); + } + }); + + grp1.add(orgLicSel); + orgLicSel.setText("No, but my school or work might have one"); + orgLicSel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + orgLicSelActionPerformed(evt); + } + }); + + grp1.add(noLicSel); + noLicSel.setSelected(true); + noLicSel.setText("No, I don't have a license"); + noLicSel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + noLicSelActionPerformed(evt); + } + }); + + emailBox.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR)); + emailBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + emailBoxActionPerformed(evt); + } + }); + emailBox.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent evt) { + emailBoxKeyPressed(evt); + } + }); + + emailLbl.setText("Great! Enter your email address and we'll get things set up."); + + contBtn.setText("Continue"); + contBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + contBtnActionPerformed(evt); + } + }); + + exitBtn.setText("Exit"); + exitBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exitBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(emailBox, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(noLicSel) + .addComponent(orgLicSel) + .addComponent(singLicSel) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(emailLbl)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 28, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(contBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(exitBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(18, 18, 18)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(singLicSel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(orgLicSel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(noLicSel) + .addGap(17, 17, 17) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(emailLbl) + .addComponent(exitBtn)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(emailBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(contBtn)) + .addGap(20, 20, 20)) + ); + + emailBox.setVisible(false); + emailLbl.setVisible(false); + + pack(); + }//
//GEN-END:initComponents + + private void singLicSelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_singLicSelActionPerformed + emailLbl.setVisible(true); + emailBox.setVisible(true); + emailLbl.setText("Great! Now just enter your email address."); + }//GEN-LAST:event_singLicSelActionPerformed + + private void orgLicSelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgLicSelActionPerformed + emailLbl.setVisible(true); + emailBox.setVisible(true); + emailLbl.setText("OK, enter your school or work email address."); + }//GEN-LAST:event_orgLicSelActionPerformed + + private void noLicSelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_noLicSelActionPerformed + emailLbl.setVisible(false); + emailBox.setVisible(false); + }//GEN-LAST:event_noLicSelActionPerformed + + private void openShop() { + if (Desktop.isDesktopSupported()) { + try { + Desktop.getDesktop().browse(new URI(MainGUI.API_URL + "shoplink.php")); + } catch (IOException | URISyntaxException ex) { + JOptionPane.showInternalMessageDialog(this, "Please go to symatapp.com to purchase a license."); + } + } else { + JOptionPane.showInternalMessageDialog(this, "Please go to symatapp.com to purchase a license."); + } + } + + private void contBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_contBtnActionPerformed + if (noLicSel.isSelected()) { + if (PrefStorage.getSetting("licensetype").equals("demo") + && PrefStorage.getSetting("licensedemo").equals("used")) { + int ans = JOptionPane.showInternalConfirmDialog(this, + "You have already used a trial license." + + "\nWould you like to purchase a license?", + "Expired", + JOptionPane.YES_NO_OPTION); + if (ans == JOptionPane.NO_OPTION) { + + } else { + openShop(); + } + } else { + int ans = JOptionPane.showInternalConfirmDialog(this, + "Would you like to open the shop and" + + " purchase a license?", + "Open Browser", + JOptionPane.YES_NO_OPTION); + if (ans == JOptionPane.NO_OPTION) { + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + c.add(Calendar.DATE, 15); // Adds 15 days + + PrefStorage.saveSetting("licensetype", "demo"); + PrefStorage.saveSetting("license", String.valueOf(c.getTimeInMillis())); + PrefStorage.saveSetting("licensedemo", "used"); + JOptionPane.showInternalMessageDialog(this, + "A trial license of 15 days has been activated.", + "Activated", + JOptionPane.INFORMATION_MESSAGE); + exit(); + } else { + openShop(); + } + } + } else { + if (checkRegex()) { + new CheckThread(emailBox.getText()).start(); + } + } + }//GEN-LAST:event_contBtnActionPerformed + + private void emailBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_emailBoxActionPerformed + checkRegex(); + }//GEN-LAST:event_emailBoxActionPerformed + + private void emailBoxKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_emailBoxKeyPressed + checkRegex(); + }//GEN-LAST:event_emailBoxKeyPressed + + private void exitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitBtnActionPerformed + int result = JOptionPane.showInternalConfirmDialog(this, + "Are you sure you want to exit SyMAT?", + "Quit", + JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + System.exit(0); + } + }//GEN-LAST:event_exitBtnActionPerformed + + private boolean checkRegex() { + String regex = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]+$"; + if (emailBox.getText().matches(regex)) { + contBtn.setEnabled(true); + return true; + } else { + contBtn.setEnabled(false); + return false; + } + } + + public void exit() { + MainGUI.updateNamemark(); // Make sure it displays trial or not + dispose(); + } + + /** + * Check the email address for a license. + */ + private class CheckThread extends Thread { + + private String email; + + public CheckThread(String useremail) { + email = useremail; + } + + @Override + public void run() { + try { + Debug.println("Checking license..."); + URL url = new URL(API_URL + "liccheck.php?email=" + email); + InputStream is = url.openStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line = br.readLine(); + br.close(); + is.close(); + + switch (line) { + case "ok:single": + success("single"); + break; + case "ok:domain": + success("domain"); + break; + case "checkemail": + email(); + break; + default: + fail(); + } + } catch (IOException e) { + Debug.printerr("License check failed."); + Debug.stacktrace(e); + ioerror(); + } + } + + private void success(String type) { + PrefStorage.saveSetting("license", email); + PrefStorage.saveSetting("licensetype", type); + JOptionPane.showInternalMessageDialog(MainGUI.mainPane, + "Thank you for activating SyMAT!", + "Success", + JOptionPane.INFORMATION_MESSAGE); + exit(); + } + + private void fail() { + JOptionPane.showInternalMessageDialog(MainGUI.mainPane, + "There is not a valid license for that email address.", + "Activation failure", + JOptionPane.ERROR_MESSAGE); + } + + private void email() { + try { + String code = JOptionPane.showInternalInputDialog(MainGUI.mainPane, + "A code has been emailed to you. " + + "Enter it below to verify.", + "Almost done!", + JOptionPane.QUESTION_MESSAGE); + Debug.println("Checking license code (" + code + ")..."); + URL url = new URL(API_URL + "emailverify.php?code=" + code + "&email=" + email); + InputStream is = url.openStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line = br.readLine(); + br.close(); + is.close(); + if (code.equals(line)) { + success("domain"); + } else { + JOptionPane.showInternalMessageDialog(MainGUI.mainPane, + "Code invalid.", + "Error", + JOptionPane.ERROR_MESSAGE); + } + } catch (IOException ex) { + ioerror(); + } + } + + private void ioerror() { + JOptionPane.showMessageDialog(MainGUI.mainPane, + "An error occured while verifying your license. " + + "Ensure you have an Internet connection and " + + "try again later.", + "Error", + JOptionPane.ERROR_MESSAGE); + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton contBtn; + private javax.swing.JTextField emailBox; + private javax.swing.JLabel emailLbl; + private javax.swing.JButton exitBtn; + private javax.swing.ButtonGroup grp1; + private javax.swing.JLabel jLabel1; + private javax.swing.JRadioButton noLicSel; + private javax.swing.JRadioButton orgLicSel; + private javax.swing.JRadioButton singLicSel; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/MainGUI.java b/src/net/apocalypselabs/symat/MainGUI.java index ae9b605..2e57357 100644 --- a/src/net/apocalypselabs/symat/MainGUI.java +++ b/src/net/apocalypselabs/symat/MainGUI.java @@ -36,6 +36,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; +import java.util.Calendar; +import java.util.Date; import javax.swing.ImageIcon; import javax.swing.JInternalFrame; @@ -48,6 +50,7 @@ public class MainGUI extends javax.swing.JFrame { public static final String APP_NAME = "SyMAT 0.9"; public static final double APP_CODE = 10; public static final String VERSION_NAME = "0.9"; + public static final String API_URL = "https://apis.symatapp.com/"; public static String argfile = ""; public static boolean skipPython = false; // Skip python init on start? public static boolean skipEditor = false; // Skip editor init on start? @@ -64,7 +67,8 @@ public class MainGUI extends javax.swing.JFrame { // Check for updates. try { - URL url = new URL("http://symatapp.com/version.txt"); + Debug.println("Checking for updates..."); + URL url = new URL(API_URL + "version.php"); InputStream is = url.openStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); @@ -78,8 +82,11 @@ public class MainGUI extends javax.swing.JFrame { System.out.println("An update was found, " + "but has been ignored by the user."); } else { + Debug.println("Update available."); loadFrame(new Update(line.split("\\|")[1])); } + } else { + Debug.println("No updates found."); } } catch (IOException | NumberFormatException e) { System.err.println("Fail: Cannot check update server. \n" @@ -89,15 +96,38 @@ public class MainGUI extends javax.swing.JFrame { setButtonShortcuts(); - // Open shell unless launched with file as argument - if (argfile.equals("")) { - Interpreter sh = new Interpreter(); - loadFrame(sh); - } else { + // Open initial windows + boolean loaded = false; + if (!argfile.equals("")) { CodeEditor ed = new CodeEditor(); loadFrame(ed); ed.openFileFromName(argfile); argfile = ""; + loaded = true; + } + if (PrefStorage.getSetting("license").equals("") + || PrefStorage.getSetting("licensetype").equals("demo")) { + boolean licValid = false; + if (PrefStorage.getSetting("licensetype").equals("demo")) { + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + try { + long expire = Long.parseLong(PrefStorage.getSetting("license")); + if (expire > c.getTimeInMillis()) { + licValid = true; + } + } catch (NumberFormatException e) { + + } + } + if (!licValid) { + loadFrame(new FirstRun()); + loaded = true; + } + } + // Only load shell if nothing else is going on + if (argfile.equals("") && !loaded) { + loadFrame(new Interpreter()); } updateDisplay(); } @@ -134,16 +164,25 @@ public class MainGUI extends javax.swing.JFrame { */ private static String namemark() { String nbsp = ""; + String demo = ""; for (int i = 0; i < 8; i++) { nbsp += " "; } + if (PrefStorage.getSetting("licensetype").equals("demo")) { + demo = " Trial"; + } return "" + nbsp + "" - + APP_NAME + + APP_NAME + demo + "  "; } + public static void updateNamemark() { + jLabel1.setText(namemark()); + jLabel3.setText(namemark()); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -535,8 +574,11 @@ public class MainGUI extends javax.swing.JFrame { skipPython = true; skipEditor = true; break; + case "licensereset": + PrefStorage.saveSetting("license", ""); + break; default: - argfile = args[0]; + argfile = arg; break; } }