Skip to content

Commit

Permalink
Add delete certificate action and enhance export functionality
Browse files Browse the repository at this point in the history
Introduced a new 'Delete' action for certificates in the plugin. Enhanced the export functionality to allow saving the certificate to a specified file location, and added logging for better error tracking.
  • Loading branch information
cortiz committed Sep 14, 2024
1 parent d11a6a1 commit 000ac3d
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 19 deletions.
3 changes: 2 additions & 1 deletion src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private JPanel createUnlockButton() {
this.passwordField = new JBPasswordField();
panel.setBorder(JBUI.Borders.customLineBottom(JBUI.CurrentTheme.Toolbar.SEPARATOR_COLOR));
JButton unlockButton = getButton(passwordField, panel);
JLabel passwordLabel = new JBLabel("Enter password: ");
JBLabel passwordLabel = new JBLabel("Enter password: ");
passwordField.requestFocusInWindow();

// Set focus traversal keys for the password field to move to the unlock button
Expand Down Expand Up @@ -211,6 +211,7 @@ public void addCertificate(String alias, X509Certificate certificate) {
public String getSelectedCertificate() {
return list.getSelectedValue();
}

public void removeCertificate(String alias) {
listModel.remove(listModel.indexOf(alias));
certs.remove(alias);
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/com/jmpeax/ssltoolbox/jks/actions/DeletetCert.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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.ui.Messages;
import com.jmpeax.ssltoolbox.jks.JKSView;
import com.jmpeax.ssltoolbox.svc.CertificateHelper;
import org.jetbrains.annotations.NotNull;

public class DeletetCert 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");
return;
}
var selectedAlias = view.getSelectedCertificate();
if (selectedAlias == null) {
Messages.showErrorDialog("No certificate selected", "No Certificate Selected");
return;
}
var pwd = Messages.showPasswordDialog("Keystore password", "KeyStore Password");
if (pwd != null && !pwd.isBlank()) {
certificateHelper.removeCertificate(ksVirtualFile, selectedAlias,pwd.toCharArray());
view.removeCertificate(selectedAlias);
Messages.showInfoMessage("Certificate removed", "Certificate Removed");
}
}



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;
}
}
45 changes: 31 additions & 14 deletions src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@
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.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.jmpeax.ssltoolbox.jks.JKSView;
import com.jmpeax.ssltoolbox.svc.CertificateHelper;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Objects;

public class ExportCert extends AnAction {

private static final Logger LOGGER = LoggerFactory.getLogger(ExportCert.class);

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Expand All @@ -28,24 +32,37 @@ public void actionPerformed(@NotNull AnActionEvent e) {
var view = getViewComponent(e);
if (view == null) {
Messages.showErrorDialog("No JKS view found", "No JKS View");
return;
}
var selectedAlias = view.getSelectedCertificate();
if (selectedAlias == null) {
Messages.showErrorDialog("No certificate selected", "No Certificate Selected");
return;
}
var descriptor = new FileChooserDescriptor(
false, // Choose Files
true,
false,
false,
false,
false
);
var descriptor = new FileSaverDescriptor("Export Certificate", "Export certificate", "cer");

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);
var f = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, view).save(selectedAlias + ".cer");
var cert = certificateHelper.exportCertificateToByte(ksVirtualFile, selectedAlias, pwd.toCharArray());
if (f != null) {
ApplicationManager.getApplication().runWriteAction(() -> writeFile(f, cert));
Messages.showInfoMessage("Certificate exported", "Certificate Exported");
} else {
Messages.showErrorDialog("No file selected", "No File Selected");
}
}
}

private void writeFile(VirtualFileWrapper f, ByteArrayOutputStream cert) {
try {
var file = f.getVirtualFile(true);
if (file != null) {
file.setBinaryContent(cert.toByteArray());
}
} catch (IOException e) {
LOGGER.error("Error writing file", e);
Messages.showErrorDialog("Error writing file", "Error Writing File");
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/jmpeax/ssltoolbox/pem/PemView.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jmpeax.ssltoolbox.pem;

import com.intellij.ui.components.JBPanel;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.JBUI;
import com.jmpeax.ssltoolbox.utils.Messages;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -35,7 +36,7 @@
* This method is used to create the text fields displaying the certificate details in the panel.
* <p>
* The `PemView` class does not provide any public methods or properties other than the constructor.*/
public class PemView extends JBPanel {
public class PemView extends JBPanel<PemView> {

public PemView(@NotNull X509Certificate certificate) {
super(new GridBagLayout());
Expand Down Expand Up @@ -138,9 +139,10 @@ private String formatDate(Date date) {
return isoFormatter.format(offsetDateTime);
}

private JTextField buildText(String text){
var textField = new JTextField(text,30);
private JBTextField buildText(String text){
var textField = new JBTextField(text,30);
textField.setEditable(false);
textField.setCaretPosition(0);
return textField;
}

Expand Down
37 changes: 36 additions & 1 deletion src/main/java/com/jmpeax/ssltoolbox/svc/CertificateHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public void importCertificate(@NotNull VirtualFile keyStoreFile, @NotNull Virtua
public @Nullable X509Certificate exportCertificate(VirtualFile ksVirtualFile,
String selectedAlias,
char[] password) {
try(var is = ksVirtualFile.getInputStream()) {
try (var is = ksVirtualFile.getInputStream()) {
var keystore = openKeyStore(is, password);
var cert = keystore.getCertificate(selectedAlias);
return (X509Certificate) cert;
Expand All @@ -171,4 +171,39 @@ public void importCertificate(@NotNull VirtualFile keyStoreFile, @NotNull Virtua
return null;
}
}

public @NotNull ByteArrayOutputStream exportCertificateToByte(VirtualFile ksVirtualFile,
String selectedAlias,
char[] password) {
var cert = exportCertificate(ksVirtualFile, selectedAlias, password);
if (cert == null) {
return new ByteArrayOutputStream();
}
return exportCertificate(cert);
}

public @NotNull ByteArrayOutputStream exportCertificate(@NotNull X509Certificate certificate) {
try {
var out = new ByteArrayOutputStream();
out.write("-----BEGIN CERTIFICATE-----\n".getBytes());
out.write(Base64.getEncoder().encode(certificate.getEncoded()));
out.write("\n-----END CERTIFICATE-----\n".getBytes());
return out;
} catch (Exception e) {
LOGGER.error("Error exporting certificate", e);
return new ByteArrayOutputStream();
}
}

public void removeCertificate(VirtualFile ksVirtualFile, String certAlias, char[] password) {
try (var is = ksVirtualFile.getInputStream();
var out = Files.newOutputStream(ksVirtualFile.toNioPath(), StandardOpenOption.WRITE)) {
var keystore = openKeyStore(is, password);
keystore.deleteEntry(certAlias);
keystore.store(out, password);
ksVirtualFile.refresh(false, false);
} catch (Exception e) {
LOGGER.error("Error removing certificate", e);
}
}
}
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
text="Export" description="Export certificate"
icon="AllIcons.Ide.OutgoingChangesOn">
</action>
<action id="delete-cert-jks" class="com.jmpeax.ssltoolbox.jks.actions.DeletetCert"
text="Delete" description="Delete certificate"
icon="AllIcons.Ide.Notification.CloseHover">
</action>
</group>

</actions>
Expand Down

0 comments on commit 000ac3d

Please sign in to comment.