From d11a6a10c314462bcf6a5d1a94a570ebde6b81a6 Mon Sep 17 00:00:00 2001 From: Carlos Ortiz Date: Thu, 12 Sep 2024 20:27:43 -0600 Subject: [PATCH] Add export certificate functionality Added the ability to export certificates from the JKS store. Updated the plugin.xml to include the export action and implemented relevant methods in JKSView and CertificateHelper to handle the export process. --- .../com/jmpeax/ssltoolbox/jks/JKSView.java | 21 +++++-- .../ssltoolbox/jks/actions/ExportCert.java | 58 +++++++++++++++++++ .../ssltoolbox/jks/actions/ImportCert.java | 4 +- .../ssltoolbox/svc/CertificateHelper.java | 13 +++++ src/main/resources/META-INF/plugin.xml | 6 +- 5 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java diff --git a/src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java b/src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java index 484021f..1dcf5c5 100644 --- a/src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java +++ b/src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java @@ -1,7 +1,6 @@ package com.jmpeax.ssltoolbox.jks; import com.intellij.icons.AllIcons; -import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -10,7 +9,6 @@ import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBPasswordField; import com.intellij.util.ui.JBUI; -import com.jmpeax.ssltoolbox.jks.actions.ImportCert; import com.jmpeax.ssltoolbox.pem.PemView; import com.jmpeax.ssltoolbox.svc.CertificateHelper; import org.jetbrains.annotations.NotNull; @@ -28,6 +26,7 @@ import java.util.Set; public class JKSView extends JPanel { + private JBList list; private PemView pemView; private final VirtualFile file; @@ -141,7 +140,7 @@ private JPanel createUnlockButton() { try { var certificateHelper = ApplicationManager.getApplication().getService(CertificateHelper.class); this.certs = certificateHelper.getKeyStoreCerts(file.getInputStream(), password); - updateView(certs); + addCertificate(certs); panel.removeAll(); panel.add(buildToolBar()); revalidate(); @@ -174,7 +173,7 @@ private JPanel buildToolBar() { } - private void updateView(Map certs) { + private void addCertificate(Map certs) { certs.keySet().forEach(listModel::addElement); list = new JBList<>(listModel); list.setCellRenderer(new IconListRenderer()); @@ -189,7 +188,6 @@ private void updateView(Map certs) { }); listPanel.removeAll(); listPanel.add(new JScrollPane(list), BorderLayout.CENTER); - } public @Nullable JComponent getUnlockText() { @@ -204,4 +202,17 @@ public Component getListCellRendererComponent(JList list, Object value, int i return label; } } + + public void addCertificate(String alias, X509Certificate certificate) { + listModel.addElement(alias); + certs.put(alias, certificate); + } + + public String getSelectedCertificate() { + return list.getSelectedValue(); + } + public void removeCertificate(String alias) { + listModel.remove(listModel.indexOf(alias)); + certs.remove(alias); + } } \ No newline at end of file diff --git a/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java b/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java new file mode 100644 index 0000000..ffc95e6 --- /dev/null +++ b/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java @@ -0,0 +1,58 @@ +package com.jmpeax.ssltoolbox.jks.actions; + + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vfs.VirtualFile; +import com.jmpeax.ssltoolbox.jks.JKSView; +import com.jmpeax.ssltoolbox.svc.CertificateHelper; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.Objects; + +public class ExportCert extends AnAction { + + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + + var certificateHelper = ApplicationManager.getApplication().getService(CertificateHelper.class); + var ksVirtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE); + var view = getViewComponent(e); + if (view == null) { + Messages.showErrorDialog("No JKS view found", "No JKS View"); + } + var selectedAlias = view.getSelectedCertificate(); + if (selectedAlias == null) { + Messages.showErrorDialog("No certificate selected", "No Certificate Selected"); + } + var descriptor = new FileChooserDescriptor( + false, // Choose Files + true, + false, + false, + false, + false + ); + var pwd = Messages.showPasswordDialog("Keystore password", "KeyStore Password"); + if (pwd != null && !pwd.isBlank()) { + certificateHelper.exportCertificate(ksVirtualFile, selectedAlias, pwd.toCharArray()); + Messages.showInfoMessage("Certificate exported", "Certificate Exported"); + view.removeCertificate(selectedAlias); + } + } + + private JKSView getViewComponent(@NotNull AnActionEvent e) { + // Retrieve your view component from context, e.g., using the data context from the event + return e.getData(PlatformDataKeys.CONTEXT_COMPONENT) instanceof JKSView + ? (JKSView) e.getData(PlatformDataKeys.CONTEXT_COMPONENT) + : null; + } +} diff --git a/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ImportCert.java b/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ImportCert.java index 3cfb352..7fa398a 100644 --- a/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ImportCert.java +++ b/src/main/java/com/jmpeax/ssltoolbox/jks/actions/ImportCert.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.util.Objects; public class ImportCert extends AnAction { @@ -53,7 +54,8 @@ public void actionPerformed(@NotNull AnActionEvent e) { if (pwd != null && !pwd.isBlank()) { certificateHelper.importCertificate(ksVirtualFile, file,selectedAlias.getInput(), pwd.toCharArray()); Messages.showInfoMessage("Certificate imported", "Certificate Imported"); - getViewComponent(e); + Objects.requireNonNull(getViewComponent(e)).addCertificate(selectedAlias.getInput(), + certificateHelper.getCertificate(file).stream().findFirst().orElseThrow()); } } catch (IOException ex) { diff --git a/src/main/java/com/jmpeax/ssltoolbox/svc/CertificateHelper.java b/src/main/java/com/jmpeax/ssltoolbox/svc/CertificateHelper.java index f28fa04..b3c2a44 100644 --- a/src/main/java/com/jmpeax/ssltoolbox/svc/CertificateHelper.java +++ b/src/main/java/com/jmpeax/ssltoolbox/svc/CertificateHelper.java @@ -4,6 +4,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.security.auth.x500.X500Principal; import java.io.*; @@ -156,6 +157,18 @@ public void importCertificate(@NotNull VirtualFile keyStoreFile, @NotNull Virtua } catch (Exception e) { LOGGER.error("Error importing certificate", e); } + } + public @Nullable X509Certificate exportCertificate(VirtualFile ksVirtualFile, + String selectedAlias, + char[] password) { + try(var is = ksVirtualFile.getInputStream()) { + var keystore = openKeyStore(is, password); + var cert = keystore.getCertificate(selectedAlias); + return (X509Certificate) cert; + } catch (Exception e) { + LOGGER.error("Error exporting certificate", e); + return null; + } } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 6f8db05..a699d1c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -64,7 +64,11 @@ popup="true" icon="AllIcons.Ide.ConfigFile"> + icon="AllIcons.Ide.IncomingChangesOn"> + +