diff --git a/app/lib/commons-codec-1.2.jar b/app/lib/commons-codec-1.2.jar deleted file mode 100644 index cce1e07c7..000000000 Binary files a/app/lib/commons-codec-1.2.jar and /dev/null differ diff --git a/app/lib/commons-codec-1.7.jar b/app/lib/commons-codec-1.7.jar new file mode 100644 index 000000000..efa7f7291 Binary files /dev/null and b/app/lib/commons-codec-1.7.jar differ diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 4e5ff6d76..f00b02573 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -829,6 +829,13 @@ public class Preferences { */ } + public static boolean has(String key) { + return table.containsKey(key); + } + + public static void remove(String key) { + table.remove(key); + } static public String getDefault(String attribute) { return (String) defaults.get(attribute); @@ -976,5 +983,5 @@ public class Preferences { { return new PreferencesMap(table); } - + } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 54fbf7f11..915f58237 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -23,8 +23,10 @@ package processing.app; +import org.apache.commons.codec.digest.DigestUtils; import processing.app.debug.*; import processing.app.debug.Compiler; +import processing.app.forms.PasswordAuthorizationDialog; import processing.app.helpers.PreferencesMap; import processing.app.packages.Library; import processing.app.packages.LibraryList; @@ -1598,9 +1600,9 @@ public class Sketch { // } editor.status.progressNotice(_("Uploading...")); - upload(appletPath, foundName, usingProgrammer); + boolean success = upload(appletPath, foundName, usingProgrammer); editor.status.progressUpdate(100); - return true; + return success; } @@ -1656,16 +1658,33 @@ public class Sketch { System.out.println(_("Low memory available, stability problems may occur")); } - protected String upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws RunnerException, SerialException { + protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws RunnerException, SerialException { TargetPlatform target = Base.getTargetPlatform(); String board = Preferences.get("board"); Uploader uploader = new UploaderFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port")); + if (uploader.requiresAuthorization() && !Preferences.has(uploader.getAuthorizationKey())) { + PasswordAuthorizationDialog dialog = new PasswordAuthorizationDialog(editor); + dialog.setLocationRelativeTo(editor); + dialog.setVisible(true); + + if (dialog.isCancelled()) { + editor.statusNotice(_("Upload cancelled")); + return false; + } + + Preferences.set(uploader.getAuthorizationKey(), DigestUtils.sha512Hex(dialog.getPassword())); + } + boolean success = uploader.uploadUsingPreferences(buildPath, suggestedClassName, usingProgrammer); - return success ? suggestedClassName : null; + if (uploader.requiresAuthorization() && !success) { + Preferences.remove(uploader.getAuthorizationKey()); + } + + return success; } diff --git a/app/src/processing/app/debug/HttpUploader.java b/app/src/processing/app/debug/HttpUploader.java index f3fbe222f..cf846d855 100644 --- a/app/src/processing/app/debug/HttpUploader.java +++ b/app/src/processing/app/debug/HttpUploader.java @@ -6,6 +6,7 @@ import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; +import processing.app.Preferences; import processing.app.SerialException; import java.io.File; @@ -32,6 +33,14 @@ public class HttpUploader extends Uploader { this.ipAddress = matcher.group(1); } + public boolean requiresAuthorization() { + return true; + } + + public String getAuthorizationKey() { + return "pwd." + ipAddress; + } + @Override public boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer) throws RunnerException, SerialException { if (usingProgrammer) { @@ -41,13 +50,14 @@ public class HttpUploader extends Uploader { FilePart filePart; try { - filePart = new FilePart("sketch.hex", new File(buildPath, className + ".hex")); + filePart = new FilePart("sketch", new File(buildPath, className + ".hex")); } catch (FileNotFoundException e) { throw new RunnerException(e); } Part[] parts = {filePart}; PostMethod post = newPostMethod(); + post.setRequestHeader("Cookie", "pwd=" + Preferences.get(getAuthorizationKey())); post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams())); int statusCode; @@ -58,7 +68,6 @@ public class HttpUploader extends Uploader { } if (statusCode == HttpStatus.SC_OK) { - System.out.println(_("Sketch uploaded")); return true; } @@ -71,7 +80,7 @@ public class HttpUploader extends Uploader { } protected PostMethod newPostMethod() { - return new PostMethod("http://" + ipAddress + ":8000/upload"); + return new PostMethod("http://" + ipAddress + ":6571/upload"); } @Override diff --git a/app/src/processing/app/debug/Uploader.java b/app/src/processing/app/debug/Uploader.java index 50d7a5e13..9073b2d6c 100644 --- a/app/src/processing/app/debug/Uploader.java +++ b/app/src/processing/app/debug/Uploader.java @@ -48,14 +48,22 @@ public abstract class Uploader implements MessageConsumer { static InputStream serialInput; static OutputStream serialOutput; - + boolean verbose; public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer) throws RunnerException, SerialException; - + public abstract boolean burnBootloader() throws RunnerException; - + + public boolean requiresAuthorization() { + return false; + } + + public String getAuthorizationKey() { + return null; + } + protected void flushSerialBuffer() throws RunnerException, SerialException { // Cleanup the serial buffer try { @@ -76,7 +84,7 @@ public abstract class Uploader implements MessageConsumer { serialPort.setDTR(true); serialPort.setRTS(true); - + serialPort.dispose(); } catch (SerialNotFoundException e) { throw e; @@ -93,14 +101,14 @@ public abstract class Uploader implements MessageConsumer { return executeUploadCommand(commandArray); } - protected boolean executeUploadCommand(String commandArray[]) + protected boolean executeUploadCommand(String commandArray[]) throws RunnerException { firstErrorFound = false; // haven't found any errors yet secondErrorFound = false; notFoundError = false; int result=0; // pre-initialized to quiet a bogus warning from jikes - + try { if (verbose || Preferences.getBoolean("upload.verbose")) { for(int i = 0; i < commandArray.length; i++) { @@ -122,10 +130,10 @@ public abstract class Uploader implements MessageConsumer { compiling = false; } catch (InterruptedException intExc) { } - } + } if(exception!=null) { exception.hideStackTrace(); - throw exception; + throw exception; } if(result!=0) return false; @@ -171,16 +179,16 @@ public abstract class Uploader implements MessageConsumer { public void message(String s) { // selectively suppress a bunch of avrdude output for AVR109/Caterina that should already be quelled but isn't - if (!Preferences.getBoolean("upload.verbose") && ( + if (!Preferences.getBoolean("upload.verbose") && ( s.indexOf("Connecting to programmer:") != -1 || s.indexOf("Found programmer: Id = \"CATERIN\"; type = S") != -1 || s.indexOf("Software Version = 1.0; No Hardware Version given.") != -1 || s.indexOf("Programmer supports auto addr increment.") != -1 || - s.indexOf("Programmer supports buffered memory access with buffersize=128 bytes.") != -1 || - s.indexOf("Programmer supports the following devices:") != -1 || + s.indexOf("Programmer supports buffered memory access with buffersize=128 bytes.") != -1 || + s.indexOf("Programmer supports the following devices:") != -1 || s.indexOf("Device code: 0x44") != -1)) - s = ""; - + s = ""; + System.err.print(s); // ignore cautions diff --git a/app/src/processing/app/forms/PasswordAuthorizationDialog.java b/app/src/processing/app/forms/PasswordAuthorizationDialog.java new file mode 100644 index 000000000..e0b866415 --- /dev/null +++ b/app/src/processing/app/forms/PasswordAuthorizationDialog.java @@ -0,0 +1,127 @@ +package processing.app.forms; + +import processing.app.Base; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import static processing.app.I18n._; + +public class PasswordAuthorizationDialog extends JDialog { + + protected final JButton uploadButton; + protected final JButton cancelButton; + protected final JLabel typePasswordLabel; + protected final JLabel passwordLabel; + protected final JLabel icon; + protected final JPasswordField passwordField; + + protected boolean cancelled; + protected String password; + + public PasswordAuthorizationDialog(Frame parent) { + super(parent, true); + + this.cancelled = false; + this.password = null; + + typePasswordLabel = new JLabel(); + icon = new JLabel(); + passwordLabel = new JLabel(); + passwordField = new JPasswordField(); + uploadButton = new JButton(); + cancelButton = new JButton(); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + + typePasswordLabel.setText(_("Type board password to upload a new sketch")); + + icon.setIcon(new ImageIcon(new File(Base.getContentFile("lib"), "theme/lock.png").getAbsolutePath())); + + passwordLabel.setText(_("Password:")); + + passwordField.setText(""); + passwordField.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + uploadButtonPressed(evt); + } + }); + + uploadButton.setText(_("Upload")); + uploadButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + uploadButtonPressed(evt); + } + }); + + cancelButton.setText(_("Cancel")); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + cancelButtonPressed(evt); + } + }); + + GroupLayout layout = new GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(icon, GroupLayout.PREFERRED_SIZE, 66, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(typePasswordLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(passwordLabel) + .addGap(4, 4, 4) + .addComponent(passwordField, GroupLayout.PREFERRED_SIZE, 300, GroupLayout.PREFERRED_SIZE))) + .addContainerGap(20, Short.MAX_VALUE)) + .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(cancelButton) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(uploadButton) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(icon) + .addComponent(typePasswordLabel)) + .addGap(5, 5, 5) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(passwordLabel) + .addComponent(passwordField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(uploadButton)) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + } + + private void cancelButtonPressed(ActionEvent event) { + this.cancelled = true; + this.dispose(); + } + + public void uploadButtonPressed(ActionEvent event) { + this.password = new String(passwordField.getPassword()); + this.dispose(); + } + + public String getPassword() { + return this.password; + } + + public boolean isCancelled() { + return cancelled; + } +} \ No newline at end of file