/* * eID Applet Project. * Copyright (C) 2008-2009 FedICT. * Copyright (C) 2014-2015 e-Contract.be BVBA. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version * 3.0 as published by the Free Software Foundation. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, see * http://www.gnu.org/licenses/. */ package be.fedict.eid.applet; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.Timer; import be.fedict.eid.applet.Messages.MESSAGE_ID; /** * Holds the implementation of some eID related dialogs. * * @author Frank Cornelis * */ public class Dialogs { /* * TODO: should somehow also be declared in the View interface. */ public static final int MIN_PIN_SIZE = 4; public static final int MAX_PIN_SIZE = 12; public static final int PUK_SIZE = 6; private final View view; private final Messages messages; public Dialogs(View view, Messages messages) { this.view = view; this.messages = messages; } public void getPuks(int retriesLeft, char[] puk1, char[] puk2) { Box mainPanel = Box.createVerticalBox(); if (-1 != retriesLeft) { Box retriesPanel = Box.createHorizontalBox(); JLabel retriesLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.RETRIES_LEFT) + ": " + retriesLeft); retriesLabel.setForeground(Color.RED); retriesPanel.add(retriesLabel); retriesPanel.add(Box.createHorizontalGlue()); mainPanel.add(retriesPanel); mainPanel.add(Box.createVerticalStrut(5)); } final JPasswordField puk1Field = new JPasswordField(8); { Box puk1Panel = Box.createHorizontalBox(); JLabel puk1Label = new JLabel("eID PUK1:"); puk1Label.setLabelFor(puk1Field); puk1Panel.add(puk1Label); puk1Panel.add(Box.createHorizontalStrut(5)); puk1Panel.add(puk1Field); mainPanel.add(puk1Panel); } mainPanel.add(Box.createVerticalStrut(5)); JPasswordField puk2Field = new JPasswordField(8); { Box puk2Panel = Box.createHorizontalBox(); JLabel puk2Label = new JLabel("eID PUK2:"); puk2Label.setLabelFor(puk2Field); puk2Panel.add(puk2Label); puk2Panel.add(Box.createHorizontalStrut(5)); puk2Panel.add(puk2Field); mainPanel.add(puk2Panel); } Component parentComponent = this.view.getParentComponent(); int result = JOptionPane.showOptionDialog(parentComponent, mainPanel, "eID PIN unblock", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null); if (result != JOptionPane.OK_OPTION) { throw new RuntimeException("operation canceled."); } try { if (puk1Field.getPassword().length != PUK_SIZE || puk2Field.getPassword().length != PUK_SIZE) { throw new RuntimeException("PUK size incorrect"); } System.arraycopy(puk1Field.getPassword(), 0, puk1, 0, PUK_SIZE); System.arraycopy(puk2Field.getPassword(), 0, puk2, 0, PUK_SIZE); } finally { Arrays.fill(puk1Field.getPassword(), (char) 0); Arrays.fill(puk2Field.getPassword(), (char) 0); } } /** * Structure to hold PIN data. * * @author Frank Cornelis * */ public static final class Pins { private final char[] oldPin; private final char[] newPin; public Pins(char[] oldPin, char[] newPin) { this.oldPin = new char[oldPin.length]; this.newPin = new char[newPin.length]; System.arraycopy(oldPin, 0, this.oldPin, 0, oldPin.length); System.arraycopy(newPin, 0, this.newPin, 0, newPin.length); } public char[] getOldPin() { return this.oldPin; } public char[] getNewPin() { return this.newPin; } } public Pins getPins(int retriesLeft) { Box mainPanel = Box.createVerticalBox(); if (-1 != retriesLeft) { Box retriesPanel = Box.createHorizontalBox(); JLabel retriesLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.RETRIES_LEFT) + ": " + retriesLeft); retriesLabel.setForeground(Color.RED); retriesPanel.add(retriesLabel); retriesPanel.add(Box.createHorizontalGlue()); mainPanel.add(retriesPanel); mainPanel.add(Box.createVerticalStrut(5)); } JPasswordField oldPinField = new JPasswordField(MAX_PIN_SIZE); { Box oldPinPanel = Box.createHorizontalBox(); JLabel oldPinLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.CURRENT_PIN) + ":"); oldPinLabel.setLabelFor(oldPinField); oldPinPanel.add(oldPinLabel); oldPinPanel.add(Box.createHorizontalStrut(5)); oldPinPanel.add(oldPinField); mainPanel.add(oldPinPanel); } mainPanel.add(Box.createVerticalStrut(5)); JPasswordField newPinField = new JPasswordField(MAX_PIN_SIZE); { Box newPinPanel = Box.createHorizontalBox(); JLabel newPinLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.NEW_PIN) + ":"); newPinLabel.setLabelFor(newPinField); newPinPanel.add(newPinLabel); newPinPanel.add(Box.createHorizontalStrut(5)); newPinPanel.add(newPinField); mainPanel.add(newPinPanel); } mainPanel.add(Box.createVerticalStrut(5)); JPasswordField new2PinField = new JPasswordField(MAX_PIN_SIZE); { Box new2PinPanel = Box.createHorizontalBox(); JLabel new2PinLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.NEW_PIN) + ":"); new2PinLabel.setLabelFor(new2PinField); new2PinPanel.add(new2PinLabel); new2PinPanel.add(Box.createHorizontalStrut(5)); new2PinPanel.add(new2PinField); mainPanel.add(new2PinPanel); } Component parentComponent = this.view.getParentComponent(); int result = JOptionPane.showOptionDialog(parentComponent, mainPanel, "Change eID PIN", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null); if (result != JOptionPane.OK_OPTION) { throw new RuntimeException("operation canceled."); } if (false == Arrays.equals(newPinField.getPassword(), new2PinField.getPassword())) { throw new RuntimeException("new PINs not equal"); } Pins pins = new Pins(oldPinField.getPassword(), newPinField.getPassword()); Arrays.fill(oldPinField.getPassword(), (char) 0); Arrays.fill(newPinField.getPassword(), (char) 0); return pins; } public char[] getPin() throws UserCancelledException { return getPin(-1); } private JFrame pinPadFrame; private JFrame secureReaderTransactionFrame; public void showPINPadFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "PIN", this.messages.getMessage(MESSAGE_ID.PIN_PAD)); } private void showPINPadFrame(int retriesLeft, String title, String message) { if (null != this.pinPadFrame) { disposePINPadFrame(); } this.pinPadFrame = new JFrame(title); JPanel panel = new JPanel() { private static final long serialVersionUID = 1L; @Override public Insets getInsets() { return new Insets(10, 30, 10, 30); } }; BoxLayout boxLayout = new BoxLayout(panel, BoxLayout.PAGE_AXIS); panel.setLayout(boxLayout); if (-1 != retriesLeft) { JLabel retriesLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.RETRIES_LEFT) + ": " + retriesLeft); retriesLabel.setForeground(Color.RED); panel.add(retriesLabel); } panel.add(new JLabel(message)); this.pinPadFrame.getContentPane().add(panel); this.pinPadFrame.pack(); this.pinPadFrame.setLocationRelativeTo(this.view.getParentComponent()); this.pinPadFrame.setAlwaysOnTop(true); this.pinPadFrame.setVisible(true); } public void disposePINPadFrame() { if (null != this.pinPadFrame) { this.pinPadFrame.dispose(); this.pinPadFrame = null; } } public char[] getPin(int retriesLeft) throws UserCancelledException { // main panel JPanel mainPanel = new JPanel() { private static final long serialVersionUID = 1L; private static final int BORDER_SIZE = 20; @Override public Insets getInsets() { return new Insets(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE); } }; BoxLayout boxLayout = new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS); mainPanel.setLayout(boxLayout); if (-1 != retriesLeft) { Box retriesPanel = Box.createHorizontalBox(); JLabel retriesLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.RETRIES_LEFT) + ": " + retriesLeft); retriesLabel.setForeground(Color.RED); retriesPanel.add(retriesLabel); retriesPanel.add(Box.createHorizontalGlue()); mainPanel.add(retriesPanel); mainPanel.add(Box.createVerticalStrut(5)); } Box passwordPanel = Box.createHorizontalBox(); JLabel promptLabel = new JLabel(this.messages.getMessage(MESSAGE_ID.LABEL_PIN) + ": "); passwordPanel.add(promptLabel); passwordPanel.add(Box.createHorizontalStrut(5)); final JPasswordField passwordField = new JPasswordField(MAX_PIN_SIZE); promptLabel.setLabelFor(passwordField); passwordPanel.add(passwordField); mainPanel.add(passwordPanel); // button panel JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) { private static final long serialVersionUID = 1L; @Override public Insets getInsets() { return new Insets(0, 0, 5, 5); } }; final JButton okButton = new JButton(this.messages.getMessage(MESSAGE_ID.OK)); okButton.setEnabled(false); buttonPanel.add(okButton); JButton cancelButton = new JButton(this.messages.getMessage(MESSAGE_ID.CANCEL)); buttonPanel.add(cancelButton); // dialog box final JDialog dialog = new JDialog((Frame) null, this.messages.getMessage(MESSAGE_ID.ENTER_PIN), true); dialog.setLayout(new BorderLayout()); dialog.getContentPane().add(mainPanel, BorderLayout.CENTER); dialog.getContentPane().add(buttonPanel, BorderLayout.SOUTH); final DialogResult dialogResult = new DialogResult(); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { dialogResult.result = DialogResult.Result.OK; dialog.dispose(); } }); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { dialogResult.result = DialogResult.Result.CANCEL; dialog.dispose(); } }); passwordField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { int pinSize = passwordField.getPassword().length; if (MIN_PIN_SIZE <= pinSize && pinSize <= MAX_PIN_SIZE) { dialogResult.result = DialogResult.Result.OK; dialog.dispose(); } } }); passwordField.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { } public void keyReleased(KeyEvent e) { int pinSize = passwordField.getPassword().length; if (MIN_PIN_SIZE <= pinSize && pinSize <= MAX_PIN_SIZE) { okButton.setEnabled(true); } else { okButton.setEnabled(false); } } public void keyTyped(KeyEvent e) { } }); dialog.pack(); dialog.setLocationRelativeTo(this.view.getParentComponent()); dialog.setAlwaysOnTop(true); dialog.addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { passwordField.requestFocus(); } }); Timer timer = new Timer(200, null); FocusDialogActionListener focusDialogActionListener = new FocusDialogActionListener(timer, passwordField); timer.addActionListener(focusDialogActionListener); timer.start(); dialog.setVisible(true); // setVisible will wait until some button or so has been pressed if (dialogResult.result == DialogResult.Result.OK) { char[] pin = passwordField.getPassword(); return pin; } throw new UserCancelledException(); } private static class DialogResult { enum Result { OK, CANCEL }; public Result result = null; } public void showPinBlockedDialog() { JOptionPane.showMessageDialog(this.view.getParentComponent(), this.messages.getMessage(MESSAGE_ID.PIN_BLOCKED), "eID card blocked", JOptionPane.ERROR_MESSAGE); } public void showPinChanged() { JOptionPane.showMessageDialog(this.view.getParentComponent(), this.messages.getMessage(MESSAGE_ID.PIN_CHANGED), "eID PIN change", JOptionPane.INFORMATION_MESSAGE); } public void showPinUnblocked() { JOptionPane.showMessageDialog(this.view.getParentComponent(), this.messages.getMessage(MESSAGE_ID.PIN_UNBLOCKED), "eID PIN unblock", JOptionPane.INFORMATION_MESSAGE); } public void showPUKPadFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "eID PIN unblock", this.messages.getMessage(MESSAGE_ID.PUK_PAD)); } public void showPINChangePadFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "eID PIN change", this.messages.getMessage(MESSAGE_ID.PIN_PAD_CHANGE)); } public void showPINModifyOldPINFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "eID PIN change", this.messages.getMessage(MESSAGE_ID.PIN_PAD_MODIFY_OLD)); } public void showPINModifyNewPINFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "eID PIN change", this.messages.getMessage(MESSAGE_ID.PIN_PAD_MODIFY_NEW)); } public void showPINModifyNewPINAgainFrame(int retriesLeft) { showPINPadFrame(retriesLeft, "eID PIN change", this.messages.getMessage(MESSAGE_ID.PIN_PAD_MODIFY_NEW_AGAIN)); } public void showSecureReaderTransactionFrame() { if (null != this.secureReaderTransactionFrame) { disposeSecureReaderTransactionFrame(); } this.secureReaderTransactionFrame = new JFrame("Transaction Confirmation"); JPanel panel = new JPanel() { private static final long serialVersionUID = 1L; @Override public Insets getInsets() { return new Insets(10, 30, 10, 30); } }; BoxLayout boxLayout = new BoxLayout(panel, BoxLayout.PAGE_AXIS); panel.setLayout(boxLayout); panel.add(new JLabel("Check the transaction message on the secure card reader.")); this.secureReaderTransactionFrame.getContentPane().add(panel); this.secureReaderTransactionFrame.pack(); this.secureReaderTransactionFrame.setLocationRelativeTo(this.view.getParentComponent()); this.secureReaderTransactionFrame.setVisible(true); } public void disposeSecureReaderTransactionFrame() { if (null != this.secureReaderTransactionFrame) { this.secureReaderTransactionFrame.dispose(); this.secureReaderTransactionFrame = null; } } }