package eu.tpmusielak.securephoto.tools; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; import eu.tpmusielak.securephoto.container.*; import eu.tpmusielak.securephoto.verification.VerificationFactorData; import eu.tpmusielak.securephoto.verification.Verifier; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.filechooser.FileFilter; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.*; import java.util.Arrays; import java.util.Map; import java.util.prefs.Preferences; /** * Created by IntelliJ IDEA. * User: Tomasz P. Musielak * Date: 22/05/12 * Time: 20:46 */ public class SPTools implements ActionListener, ChangeListener { private final static String APPLICATION_NAME = "SecurePhoto Tools"; private enum FileType { JPG, SPI, SPR, UNK; public static FileType getFileType(File file) { if (file.getName().endsWith(SPImage.DEFAULT_EXTENSION)) { return SPI; } else if (file.getName().endsWith(SPImageRoll.DEFAULT_EXTENSION)) { return SPR; } else if (file.getName().toLowerCase().endsWith("jpg")) { return JPG; } return UNK; } } private JButton openButton; private JButton exitButton; private JPanel mainPanel; private JButton prevButton; private JButton nextButton; private JPanel imagePanel; private JSplitPane splitPane; private JTextPane textPane; private JLabel imageLabel; private JSpinner frameNumberSpinner; private JLabel frameCountLabel; private JButton newSPRButton; private JButton addToSPRButton; private JButton setupButton; private JButton exportAsJPGButton; private JButton verifyButton; private static JMenuBar menuBar; private JMenu fileMenu; private JMenuItem openMenuItem, saveMenuItem, saveAsMenuItem, exitMenuItem; final JFileChooser openFileChooser = new JFileChooser(); final JFileChooser saveFileChooser = new JFileChooser(); private File currentFile; private SPImage currentSPImage; private SPImageRoll currentSPRoll; private BufferedImage currentImage; private int frameCount = 0; private int frameNumber = -1; private static JFrame mainFrame; private TextPaneHandler textPaneHandler; private SPValidatorHandler validatorHandler; Preferences preferences; protected String serverURI = "http://192.168.3.50:8000"; private void createUIComponents() { menuBar = new JMenuBar(); fileMenu = new JMenu("File"); openMenuItem = new JMenuItem("Open"); saveAsMenuItem = new JMenuItem("Save As..."); saveMenuItem = new JMenuItem("Save"); exitMenuItem = new JMenuItem("Exit"); fileMenu.setMnemonic(KeyEvent.VK_F); menuBar.add(fileMenu); openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK)); fileMenu.add(openMenuItem); fileMenu.addSeparator(); saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK)); fileMenu.add(saveMenuItem); fileMenu.add(saveAsMenuItem); fileMenu.addSeparator(); exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, KeyEvent.ALT_MASK)); fileMenu.add(exitMenuItem); } public SPTools() { openButton.addActionListener(SPTools.this); exitButton.addActionListener(SPTools.this); prevButton.addActionListener(SPTools.this); nextButton.addActionListener(SPTools.this); newSPRButton.addActionListener(SPTools.this); addToSPRButton.addActionListener(SPTools.this); setupButton.addActionListener(SPTools.this); exportAsJPGButton.addActionListener(SPTools.this); verifyButton.addActionListener(SPTools.this); splitPane.setDividerLocation(0.75d); textPane.setEditable(false); setNaviButtonsState(false); exportAsJPGButton.setEnabled(false); setFrameNumber(-1); setFrameCount(0); textPaneHandler = new TextPaneHandler(textPane); SpinnerModel model = new SpinnerNumberModel(0, 0, 0, 0); frameNumberSpinner.setModel(model); frameNumberSpinner.addChangeListener(this); validatorHandler = new SPValidatorHandler(); preferences = Preferences.userNodeForPackage(this.getClass()); } /** * Invoked when an action occurs. */ @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == openButton) { openFileAction(); } else if (source == newSPRButton) { saveFileChooser.resetChoosableFileFilters(); saveFileChooser.addChoosableFileFilter(new SPRFileFilter()); int retVal = saveFileChooser.showSaveDialog(mainPanel); if (retVal == JFileChooser.APPROVE_OPTION) { newSPR(saveFileChooser.getSelectedFile()); } } else if (source == addToSPRButton) { openFileChooser.resetChoosableFileFilters(); openFileChooser.addChoosableFileFilter(new JPGFileFilter()); openFileChooser.addChoosableFileFilter(new SPIFileFilter()); int retVal = openFileChooser.showOpenDialog(mainPanel); if (retVal == JFileChooser.APPROVE_OPTION) { addImageToSPR(openFileChooser.getSelectedFile()); } } else if (source == exportAsJPGButton) { saveFileChooser.resetChoosableFileFilters(); saveFileChooser.addChoosableFileFilter(new JPGFileFilter()); File outputFile = getFileWithoutExtension(currentFile); saveFileChooser.setSelectedFile(outputFile); int retVal = saveFileChooser.showSaveDialog(mainPanel); if (retVal == JFileChooser.APPROVE_OPTION) { exportJPG(saveFileChooser.getSelectedFile()); } saveFileChooser.setSelectedFile(null); } else if (source == prevButton) { prevButtonAction(); } else if (source == nextButton) { nextButtonAction(); } else if (source == verifyButton) { verifyButtonAction(); } else if (source == exitButton) { System.exit(0); } else if (source == frameNumberSpinner) { } else if (source == setupButton) { setupButtonAction(); } } private void verifyButtonAction() { SPImage.VerificationStatus result; if (currentSPRoll == null) { result = currentSPImage.checkIntegrity(validatorHandler); } else { result = currentSPRoll.checkIntegrity(validatorHandler); } String message; int messageType; switch (result) { case OK: message = "Hash verification positive"; messageType = JOptionPane.INFORMATION_MESSAGE; break; case FAILED: message = "Hash verification negative"; messageType = JOptionPane.ERROR_MESSAGE; break; case UNKNOWN: default: message = "Hash verification inconclusive"; messageType = JOptionPane.WARNING_MESSAGE; break; } JOptionPane.showMessageDialog(mainFrame, message, "Verification result", messageType); } @Override public void stateChanged(ChangeEvent e) { SpinnerModel model = frameNumberSpinner.getModel(); int number = (Integer) model.getValue(); setFrameNumber(number - 1); loadFrame(); displayImage(); } private void nextButtonAction() { if (currentSPRoll == null) return; frameNumberSpinner.setValue(frameNumberSpinner.getNextValue()); } private void prevButtonAction() { if (currentSPRoll == null) return; frameNumberSpinner.setValue(frameNumberSpinner.getPreviousValue()); } private void openFileAction() { resetFrameCounters(); openFileChooser.resetChoosableFileFilters(); openFileChooser.addChoosableFileFilter(new InputFileFilter()); int retVal = openFileChooser.showOpenDialog(mainPanel); if (retVal == JFileChooser.APPROVE_OPTION) { openFile(openFileChooser.getSelectedFile()); displayImage(); if (currentImage != null) exportAsJPGButton.setEnabled(true); mainFrame.setTitle(APPLICATION_NAME + " - " + currentFile.getName()); } } private void setupButtonAction() { serverURI = (String) JOptionPane.showInputDialog(null, "Enter base station address : ", "Setup", JOptionPane.PLAIN_MESSAGE, null, null, serverURI); } private void exportJPG(File file) { if (!file.getName().endsWith(".jpg")) { file = new File(file.getAbsolutePath() + ".jpg"); } try { byte[] imageData = currentSPImage.getImageData(); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(imageData); fileOutputStream.close(); // TODO: Exception handling } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void newSPR(File file) { if (!file.getName().endsWith("." + SPImageRoll.DEFAULT_EXTENSION)) { file = new File(file.getAbsolutePath() + "." + SPImageRoll.DEFAULT_EXTENSION); } SPImageRoll imageRoll = new SPImageRoll(file); openFile(file); } private void addImageToSPR(File selectedFile) { SPImage spImage = null; BufferedImage image = null; FileType fileType = FileType.getFileType(selectedFile); switch (fileType) { case SPI: try { spImage = SPImage.fromFile(selectedFile); // TODO: Exception handling } catch (IOException e) { return; } catch (ClassNotFoundException e) { return; } break; case JPG: image = openJPEGFile(selectedFile); break; default: return; } // Should never hapen if (currentSPRoll == null) return; // If currentSPImage is null create a new SPImage if (spImage == null) { //No image to load - nothing to do if (image == null) return; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { ImageIO.write(image, "jpg", byteArrayOutputStream); byte[] imageBytes = byteArrayOutputStream.toByteArray(); byteArrayOutputStream.close(); spImage = SPImage.getInstance(imageBytes, null, currentSPRoll.getCurrentHash()); } catch (IOException e) { e.printStackTrace(); return; } } // Add image to roll currentSPRoll.addImage(spImage); openFile(currentFile); } private void openFile(File file) { currentFile = file; currentSPImage = null; currentSPRoll = null; clearImage(); textPaneHandler.clear(); validatorHandler.reset(); FileType fileType = FileType.getFileType(file); switch (fileType) { case SPI: currentImage = openSPIFile(file); break; case SPR: currentImage = openSPRFile(file); break; case JPG: currentImage = openJPEGFile(file); break; default: } } private void setNaviButtonsState(boolean state) { addToSPRButton.setEnabled(state); } private BufferedImage openJPEGFile(File file) { BufferedImage image = null; try { image = ImageIO.read(file); setNaviButtonsState(false); verifyButton.setEnabled(false); } catch (IOException e) { e.printStackTrace(); } return image; } private BufferedImage openSPIFile(File file) { BufferedImage image = null; try { currentSPImage = SPImage.fromFile(file); byte[] imageBytes = currentSPImage.getImageData(); image = ImageIO.read(new ByteArrayInputStream(imageBytes)); setNaviButtonsState(false); printVerifierData(currentSPImage); verifyButton.setEnabled(true); } catch (IOException e) { textPaneHandler.showException(Arrays.toString(e.getStackTrace())); } catch (ClassNotFoundException e) { textPaneHandler.showException(Arrays.toString(e.getStackTrace())); } return image; } private BufferedImage openSPRFile(File file) { BufferedImage image = null; try { currentSPRoll = SPImageRoll.fromFile(file); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } if (currentSPRoll == null) return image; textPaneHandler.setRollInfo(currentSPRoll.toString()); addToSPRButton.setEnabled(true); verifyButton.setEnabled(true); int count = currentSPRoll.getFrameCount(); if (count < 1) return image; int frameCount = currentSPRoll.getFrameCount(); setFrameCount(frameCount); setFrameNumber(0); frameNumberSpinner.setModel(new SpinnerNumberModel(1, 1, frameCount, 1)); try { currentSPImage = currentSPRoll.getFrame(frameNumber); byte[] imageBytes = currentSPImage.getImageData(); image = ImageIO.read(new ByteArrayInputStream(imageBytes)); printVerifierData(currentSPImage); } catch (IOException e) { textPaneHandler.showException(Arrays.toString(e.getStackTrace())); } setNaviButtonsState(true); return image; } private void loadFrame() { try { currentSPImage = currentSPRoll.getFrame(frameNumber); byte[] imageBytes = currentSPImage.getImageData(); currentImage = ImageIO.read(new ByteArrayInputStream(imageBytes)); } catch (IOException e) { e.printStackTrace(); } catch (NullPointerException e) { textPaneHandler.showException("Cannot display image"); } printVerifierData(currentSPImage); } private void setFrameCount(int count) { frameCount = count; frameCountLabel.setText(String.valueOf(frameCount)); } private void setFrameNumber(int number) { frameNumber = number; if (frameNumber == (frameCount - 1)) { nextButton.setEnabled(false); } else { nextButton.setEnabled(true); } if (frameNumber <= 0) { prevButton.setEnabled(false); } else { prevButton.setEnabled(true); } } private void resetFrameCounters() { setFrameCount(0); setFrameNumber(-1); frameNumberSpinner.setModel(new SpinnerNumberModel(0, 0, 0, 0)); } public void printVerifierData(SPImage image) { if (image == null) return; StringBuilder sb = new StringBuilder(); Map<Class<Verifier>, VerificationFactorData> verificationFactorData = image.getVerificationFactorData(); for (VerificationFactorData data : verificationFactorData.values()) { sb.append(data.toString()); sb.append('\n'); } textPaneHandler.setFrameInfo(sb.toString()); } private void clearImage() { currentImage = null; imageLabel.setIcon(null); imageLabel.revalidate(); } private void displayImage() { if (currentImage == null) return; int imgHeight = currentImage.getHeight(); int imgWidth = currentImage.getWidth(); double maxDimImg = Math.max(imgHeight, imgWidth); double maxDimWindow = Math.max(imagePanel.getHeight(), imagePanel.getWidth()); double scalingFactor = maxDimWindow / maxDimImg; int scaledWidth = (int) Math.ceil(imgWidth * scalingFactor); int scaledHeight = (int) Math.ceil(imgHeight * scalingFactor); Image scaledPicture = currentImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH); imageLabel.setIcon(new ImageIcon(scaledPicture)); } private class InputFileFilter extends FileFilter { @Override public boolean accept(File f) { String name = f.getName(); int dotIndex = name.lastIndexOf('.'); String ext = name.substring(dotIndex + 1).toLowerCase(); return ext.equals(SPImage.DEFAULT_EXTENSION) || ext.equals(SPImageRoll.DEFAULT_EXTENSION) || ext.equals("jpg") || f.isDirectory(); } @Override public String getDescription() { return "SPImage, SPImageRoll or JPEG"; } } private class SPIFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().endsWith(SPImage.DEFAULT_EXTENSION); } @Override public String getDescription() { return "SPImage file (*." + SPImage.DEFAULT_EXTENSION.toLowerCase() + ")"; } } private class SPRFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().endsWith(SPImageRoll.DEFAULT_EXTENSION); } @Override public String getDescription() { return "SPImageRoll (*." + SPImageRoll.DEFAULT_EXTENSION.toLowerCase() + ")"; } } private class JPGFileFilter extends FileFilter { @Override public boolean accept(File f) { return f.isDirectory() || f.getName().endsWith("jpg"); } @Override public String getDescription() { return "JPG File (*.jpg)"; } } private class TextPaneHandler { private JTextPane textPane; private String rollInfo; private String frameInfo; public TextPaneHandler(JTextPane textPane) { this.textPane = textPane; } public void setRollInfo(String rollInfo) { this.rollInfo = rollInfo; update(); } public void setFrameInfo(String frameInfo) { this.frameInfo = frameInfo; update(); } public void clear() { rollInfo = ""; frameInfo = ""; update(); } private void update() { StringBuilder sb = new StringBuilder(); sb.append(rollInfo); sb.append('\n'); sb.append(frameInfo); textPane.setText(sb.toString()); } public void showException(String s) { textPane.setText(s); } } private class SPValidatorHandler implements SPValidator { private final String SPR_LOOKUP_PATH = "spr_retrieve"; private final String FRAME_LOOKUP_PATH = "hash_retrieve"; private StringBuilder sb; private HttpClient client; private SPValidatorHandler() { client = new DefaultHttpClient(); sb = new StringBuilder(); } private void reset() { sb = new StringBuilder(); } @Override public void log(String s) { sb.append(s).append("\n"); textPane.setText(sb.toString()); } @Override public SPRInfo lookupSPR(byte[] uniqueID) { String encodedID = Base64.encode(uniqueID); try { HttpGet request = new HttpGet(String.format("%s/%s/%s/" , serverURI, SPR_LOOKUP_PATH, encodedID)); HttpResponse response = client.execute(request); HttpEntity enty = response.getEntity(); if (enty != null) enty.consumeContent(); if (!response.containsHeader("time")) { return null; } long creationDate = Long.parseLong(response.getHeaders("time")[0].getValue()); String user = response.getHeaders("user")[0].getValue(); String deviceID = response.getHeaders("device_id")[0].getValue(); return new SPRInfo(creationDate, deviceID, encodedID, user); } catch (IOException e) { e.printStackTrace(); } return null; } @Override public FrameInfo lookupFrame(byte[] uniqueID) { String encodedID = Base64.encode(uniqueID); try { HttpGet request = new HttpGet(String.format("%s/%s/%s/" , serverURI, FRAME_LOOKUP_PATH, encodedID)); HttpResponse response = client.execute(request); HttpEntity enty = response.getEntity(); if (enty != null) enty.consumeContent(); if (!response.containsHeader("time")) { return null; } long creationDate = Long.parseLong(response.getHeaders("time")[0].getValue()); String user = response.getHeaders("user")[0].getValue(); String deviceID = response.getHeaders("device_id")[0].getValue(); String sprID = response.getHeaders("spr_id")[0].getValue(); String imageHash = response.getHeaders("image_hash")[0].getValue(); return new FrameInfo(creationDate, imageHash, deviceID, encodedID, sprID, user); } catch (IOException e) { e.printStackTrace(); } return null; } } private static File getFileWithoutExtension(File file) { String filePath = file.getAbsolutePath(); int index = filePath.lastIndexOf('.'); String filePathWithoutName = filePath.substring(0, index); return new File(filePathWithoutName); } public static void main(String[] args) { mainFrame = new JFrame(APPLICATION_NAME); mainFrame.setContentPane(new SPTools().mainPanel); mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); mainFrame.pack(); mainFrame.setJMenuBar(menuBar); mainFrame.setVisible(true); mainFrame.setResizable(false); } }