package ui.gui; import model.asn1.ASN1Object; import model.asn1.UtcTime; import model.pki.cert.Certificate; import model.pki.crl.Reason; import model.pki.crl.RevokedCertificate; import ui.gui.widgets.GCBuilder; import ui.gui.widgets.UIUtils; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Arrays; import static java.awt.GridBagConstraints.HORIZONTAL; import static java.awt.GridBagConstraints.WEST; import static ui.gui.widgets.UIUtils.alert; /** * A dialog that presents user with cert info, revocation reason, and revocation time. * +----------------------------+ * |Revoking: CN=xyz (Serial: 1)| * |Reason: (Drop Down) | * |Time: (ISO-8601 text) | * | | * | Revoke Cancel| * +----------------------------+ */ public class RevokeDialog extends JDialog { /** * ISO8601 */ private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ISO_OFFSET_DATE_TIME; /** * The incoming certificate. */ private final Certificate crt; /** * The result. */ private RevokedCertificate res; /** * Root pane */ private JPanel contentPane; /** * OK button */ private JButton buttonOK; /** * Cancel button */ private JButton buttonCancel; /** * Reason */ private JComboBox comboBoxReason; /** * Subject (not editable) */ private JTextField textFieldSubject; /** * Time */ private JFormattedTextField formattedTextFieldTime; /** * EFFECTS: Init GUI with the given cert. */ public RevokeDialog(Certificate crt) { this.crt = crt; contentPane = new JPanel(); contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS)); contentPane.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); contentPane.add(renderForm()); contentPane.add(UIUtils.createActionsPane(buttonOK = new JButton("Revoke"), buttonCancel = new JButton("Cancel"))); buttonOK.addActionListener(this::onOK); buttonCancel.addActionListener(this::onCancel); setContentPane(contentPane); setModal(true); getRootPane().setDefaultButton(buttonOK); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); setTitle("Revoke certificate"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { onCancel(null); } }); contentPane.registerKeyboardAction(this::onCancel, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); } /** * EFFECTS: Init GUI. * MODIFIES: this */ private JPanel renderForm() { final JPanel panelForm = new JPanel(); panelForm.setLayout(new GridBagLayout()); panelForm.add(new JLabel("Revoking: "), new GCBuilder().anchor(WEST).build()); panelForm.add(new JLabel("Reason: "), new GCBuilder().gridY(1).anchor(WEST).build()); panelForm.add(new JLabel("Time: "), new GCBuilder().gridY(2).anchor(WEST).build()); textFieldSubject = new JTextField(String.format("%s (Serial: %d)", crt.getCertificate().getSubject().toString(), crt.getCertificate().getSerialNumber().getLong())); textFieldSubject.setEditable(false); panelForm.add(textFieldSubject, new GCBuilder().gridX(1).anchor(WEST).fill(HORIZONTAL).build()); comboBoxReason = new JComboBox<>(Arrays.stream(Reason.values()).map(Enum::toString).toArray(String[]::new)); panelForm.add(comboBoxReason, new GCBuilder().gridXY(1, 1).anchor(WEST).fill(HORIZONTAL).build()); formattedTextFieldTime = new JFormattedTextField(DATE_FORMAT.toFormat()); formattedTextFieldTime.setText(ZonedDateTime.now().format(DATE_FORMAT)); panelForm.add(formattedTextFieldTime, new GCBuilder().gridXY(1, 2).anchor(WEST).fill(HORIZONTAL).build()); panelForm.add(new JPanel(), new GCBuilder().gridXY(1, 3).expandXY().fill(HORIZONTAL).build()); return panelForm; } /** * EFFECTS: Validate form, set result, and close dialog. * Time must be a valid ISO-8601 string with offset, and it will be converted into UTC. * Reason must be supported. * MODIFIES: this */ private void onOK(ActionEvent ev) { try { res = new RevokedCertificate(ASN1Object.TAG_SEQUENCE, null, crt.getCertificate().getSerialNumber(), new UtcTime(UtcTime.TAG, null, ZonedDateTime.parse(formattedTextFieldTime.getText(), DATE_FORMAT) .withZoneSameInstant(ZoneId.of("UTC"))), Reason.valueOf(comboBoxReason.getSelectedItem().toString())); dispose(); } catch (DateTimeParseException e) { alert(rootPane, "Revoke certificate", "Invalid time: " + formattedTextFieldTime.getText() + ". It must be a valid ISO8601 time with offset, like '1919-08-10T11:45:14+09:00'."); } catch (IllegalArgumentException e) { alert(rootPane, "Revoke certificate", "Invalid reason."); } } /** * EFFECTS: Clear the result and close dialog. * MODIFIES: this */ private void onCancel(ActionEvent ev) { res = null; dispose(); } /** * EFFECTS: Get result. */ public RevokedCertificate getRes() { return res; } }