/*
*
* Panbox - encryption for cloud storage
* Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additonally, third party code may be provided with notices and open source
* licenses from communities and third parties that govern the use of those
* portions, and any licenses granted hereunder do not alter any rights and
* obligations you may have under such open source licenses, however, the
* disclaimer of warranty and limitation of liability provisions of the GPLv3
* will apply to all the product.
*
*/
package org.panbox.desktop.common.gui;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import ezvcard.util.org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.panbox.Settings;
import org.panbox.core.crypto.randomness.SecureRandomWrapper;
import org.panbox.core.exception.RandomDataGenerationException;
import org.panbox.core.pairing.PAKCorePairingHandler;
import org.panbox.core.pairing.PairingInformation;
import org.panbox.core.pairing.PairingNotificationReceiver;
import org.panbox.core.pairing.bluetooth.BluetoothPairingInformation;
import org.panbox.core.pairing.network.NetworkPairingInformation;
import org.panbox.desktop.common.PanboxClient;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.net.InetAddress;
import java.text.MessageFormat;
import java.util.*;
import java.util.Timer;
public class PairNewDeviceDialog extends javax.swing.JDialog implements
PairingNotificationReceiver {
private static final long serialVersionUID = -6493970152852384445L;
protected static final Logger logger = Logger.getLogger("org.panbox");
private static ResourceBundle bundle = ResourceBundle.getBundle(
"org.panbox.desktop.common.gui.Messages", Settings.getInstance()
.getLocale());
private final PanboxClient client;
private final PairingInformation pInfo;
private Timer timer;
private TimerTask refreshTimeout;
private int timeout;
private String pairingPassword = null;
public PairNewDeviceDialog(JFrame parent, PanboxClient client,
PairingInformation pInfo) {
super(parent, true);
initComponents();
this.client = client;
this.pInfo = pInfo;
pairingModeSelectionComboBoxActionPerformed(new ActionEvent(this, 0,
"init"));
setVisible(true);
}
/**
* 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.
*/
// <editor-fold defaultstate="collapsed"
// desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
pairingPanel = new javax.swing.JPanel();
pairingQrCodePanel = new javax.swing.JPanel();
pairingPasswordField = new javax.swing.JTextField();
pairingModeSelectionComboBox = new javax.swing.JComboBox<>();
cancelPairingButton = new javax.swing.JButton();
statusInfoLabel = new javax.swing.JLabel();
qrCode = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(bundle.getString("client.deviceList.devicepairing.title"));
setResizable(false);
pairingPanel.setMaximumSize(new java.awt.Dimension(390, 330));
pairingPanel.setMinimumSize(new java.awt.Dimension(390, 330));
pairingQrCodePanel.setLayout(new java.awt.GridLayout(1, 1));
pairingQrCodePanel.add(qrCode);
pairingPasswordField.setText("");
pairingPasswordField.setEditable(false);
pairingModeSelectionComboBox
.setModel(new javax.swing.DefaultComboBoxModel<>(
new String[] {
bundle.getString("client.deviceList.devicepairing.slave"),
bundle.getString("client.deviceList.devicepairing.master") }));
pairingModeSelectionComboBox
.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pairingModeSelectionComboBoxActionPerformed(evt);
}
});
statusInfoLabel.setText("");
javax.swing.GroupLayout pairingPanelLayout = new javax.swing.GroupLayout(
pairingPanel);
pairingPanel.setLayout(pairingPanelLayout);
pairingPanelLayout
.setHorizontalGroup(pairingPanelLayout
.createParallelGroup(
javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(
pairingPanelLayout
.createSequentialGroup()
.addContainerGap()
.addGroup(
pairingPanelLayout
.createParallelGroup(
javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(
pairingModeSelectionComboBox,
0,
javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addComponent(
pairingQrCodePanel,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addComponent(
pairingPasswordField,
javax.swing.GroupLayout.DEFAULT_SIZE,
354,
Short.MAX_VALUE))
.addContainerGap()));
pairingPanelLayout
.setVerticalGroup(pairingPanelLayout
.createParallelGroup(
javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(
pairingPanelLayout
.createSequentialGroup()
.addContainerGap()
.addComponent(
pairingQrCodePanel,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(
javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(
pairingPasswordField,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(
javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(
pairingModeSelectionComboBox,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(331, Short.MAX_VALUE)));
cancelPairingButton.setText(bundle.getString("client.cancel"));
cancelPairingButton
.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelPairingButtonActionPerformed(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(
pairingPanel,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addGroup(
layout.createSequentialGroup()
.addComponent(
statusInfoLabel,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addPreferredGap(
javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(
cancelPairingButton)))
.addContainerGap()));
layout.setVerticalGroup(layout
.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(
layout.createSequentialGroup()
.addContainerGap()
.addComponent(pairingPanel,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addPreferredGap(
javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(
layout.createParallelGroup(
javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(
cancelPairingButton)
.addComponent(statusInfoLabel))
.addContainerGap()));
pack();
}// </editor-fold>//GEN-END:initComponents
private void pairingModeSelectionComboBoxActionPerformed(
java.awt.event.ActionEvent evt) {// GEN-FIRST:event_pairingDeviceSelectionComboBoxActionPerformed
stopRefreshTimer();
client.stopDevicePairing();
char[] keyPassword = null;
if (evt != null && !evt.getActionCommand().equals("init")
&& isMasterPairing()) {
keyPassword = PasswordEnterDialog
.invoke(PasswordEnterDialog.PermissionType.DEVICE);
if (keyPassword == null || keyPassword.length == 0) {
JOptionPane.showMessageDialog(null, bundle
.getString("PairNewDeviceDialog.cantPairWithEmptyPW"));
}
}
generateNewPasswordAndUpdateDialog();
startNewRefreshTimer();
if (isMasterPairing()) {
// Master will be paired!
client.runMasterPairingOnPairingHandle(pInfo, pairingPassword,
this, keyPassword);
} else {
// Slave will be paired!
client.runSlavePairingOnPairingHandle(pInfo, pairingPassword, this);
}
if (keyPassword != null) {
Arrays.fill(keyPassword, (char) 0);
}
}// GEN-LAST:event_pairingDeviceSelectionComboBoxActionPerformed
private void cancelPairingButtonActionPerformed(
java.awt.event.ActionEvent evt) {// GEN-FIRST:event_cancelPairingButtonActionPerformed
this.dispose();
}// GEN-LAST:event_cancelPairingButtonActionPerformed
private void generateNewPasswordAndUpdateDialog() {
try {
SecureRandomWrapper secureRandom = SecureRandomWrapper
.getInstance();
byte[] password = new byte[16];
secureRandom.nextBytes(password);
pairingPassword = Base64.encodeBase64String(password);
String addrStr = null;
if (pInfo instanceof NetworkPairingInformation) {
NetworkPairingInformation npi = (NetworkPairingInformation) pInfo;
addrStr = ((InetAddress) npi.getPairingAddress())
.getHostAddress();
} else if (pInfo instanceof BluetoothPairingInformation) {
BluetoothPairingInformation bpi = (BluetoothPairingInformation) pInfo;
addrStr = bpi.getPairingAddress().toString(); // String address
}
pairingPasswordField.setText(addrStr + ":" + pairingPassword);
BitMatrix matrix;
com.google.zxing.Writer writer = new QRCodeWriter();
matrix = writer.encode(pairingPasswordField.getText(),
com.google.zxing.BarcodeFormat.QR_CODE, 330, 330);
BufferedImage qrCodeImage = MatrixToImageWriter
.toBufferedImage(matrix);
qrCode.setIcon(new ImageIcon(qrCodeImage));
} catch (WriterException e) {
logger.fatal("PairNewDeviceDialog : Could not create the QR-Code from zxing library.", e);
} catch (RandomDataGenerationException e) {
logger.fatal("PairNewDeviceDialog : Could not obtain secure random from RNG for pairing password.", e);
}
}
private boolean isMasterPairing() {
if (pairingModeSelectionComboBox.getSelectedItem().equals(
bundle.getObject("client.deviceList.devicepairing.master"))) {
return true;
} else {
return false;
}
}
@Override
public void dispose() {
super.dispose();
client.stopDevicePairing();
stopRefreshTimer();
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelPairingButton;
private javax.swing.JComboBox<String> pairingModeSelectionComboBox;
private javax.swing.JPanel pairingPanel;
private javax.swing.JTextField pairingPasswordField;
private javax.swing.JPanel pairingQrCodePanel;
private javax.swing.JLabel qrCode;
private javax.swing.JLabel statusInfoLabel;
// End of variables declaration//GEN-END:variables
@Override
public void inform(PairingResult result) {
logger.info("PairNewDeviceDialog : Received result from pairing: "
+ result);
this.dispose();
switch (result) {
case SUCCESS:
JOptionPane
.showMessageDialog(
null,
bundle.getString("client.deviceList.devicepairing.resultmsg.success"));
break;
case TIMEOUT:
JOptionPane
.showMessageDialog(
null,
bundle.getString("client.deviceList.devicepairing.resultmsg.timeout"));
break;
case FAILED:
JOptionPane
.showMessageDialog(
null,
bundle.getString("client.deviceList.devicepairing.resultmsg.failed"));
break;
case QUITEFAILED:
// no message since error message has been shown already.
break;
default:
break;
}
}
private void startNewRefreshTimer() {
logger.debug("PairNewDeviceDialog : startNewRefreshTimer : Starting new refresh timeout timer.");
timeout = PAKCorePairingHandler.PAIRING_TIMEOUT / 1000;
refreshTimeout = new TimerTask() {
@Override
public void run() {
logger.debug("Timeout timer started... Left: " + timeout
+ " seconds.");
MessageFormat formatter = new MessageFormat("", Settings
.getInstance().getLocale());
formatter
.applyPattern(bundle
.getString("client.deviceList.devicepairing.timeoutstatusbar"));
statusInfoLabel.setText(formatter
.format(new Object[] { timeout }));
statusInfoLabel.invalidate();
timeout--;
}
};
timer = new Timer();
timer.schedule(refreshTimeout, new Date(), 1000);
}
private void stopRefreshTimer() {
if (timer != null) {
logger.debug("PairNewDeviceDialog : stopRefreshTimer : timer will be stopped NOW.");
timer.cancel();
statusInfoLabel.setText("");
statusInfoLabel.invalidate();
} else {
logger.debug("PairNewDeviceDialog : stopRefreshTimer : timer is already stopped.");
}
}
}