Skip to content

Commit

Permalink
Merge pull request #3 from cortiz/jks-import/export
Browse files Browse the repository at this point in the history
Jks import/export
  • Loading branch information
cortiz authored Sep 14, 2024
2 parents 2daf8c5 + 000ac3d commit 4a87c52
Show file tree
Hide file tree
Showing 10 changed files with 396 additions and 86 deletions.
75 changes: 26 additions & 49 deletions src/main/java/com/jmpeax/ssltoolbox/jks/JKSView.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package com.jmpeax.ssltoolbox.jks;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;

import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
Expand All @@ -18,7 +13,7 @@
import com.jmpeax.ssltoolbox.svc.CertificateHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.LoggerFactory;


import javax.swing.*;
import java.awt.*;
Expand All @@ -31,6 +26,7 @@
import java.util.Set;

public class JKSView extends JPanel {

private JBList<String> list;
private PemView pemView;
private final VirtualFile file;
Expand Down Expand Up @@ -108,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 @@ -142,8 +138,9 @@ private JPanel createUnlockButton() {
char[] password = passwordField.getPassword();
if (password != null) {
try {
this.certs = CertificateHelper.getKeyStoreCerts(file.getInputStream(), password);
updateView(certs);
var certificateHelper = ApplicationManager.getApplication().getService(CertificateHelper.class);
this.certs = certificateHelper.getKeyStoreCerts(file.getInputStream(), password);
addCertificate(certs);
panel.removeAll();
panel.add(buildToolBar());
revalidate();
Expand All @@ -160,10 +157,10 @@ private JPanel buildToolBar() {
ActionGroup actionGroup = (ActionGroup) ActionManager.getInstance().getAction("JKS-Actions");
ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("JKS-Actions-Toolbar", actionGroup, true);
actionToolBar.setTargetComponent(this);

DataContext dataContext = dataId -> this.file;
actionToolBar.getComponent().putClientProperty(DataContext.class, dataContext);


JPanel panel = new JPanel(new GridLayout(1,1));
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = JBUI.insets(5);
Expand All @@ -173,42 +170,10 @@ private JPanel buildToolBar() {
gbc.gridy = 0;
panel.add(actionToolBar.getComponent(), gbc);
return panel;
//
// JButton openButton = new JButton(AllIcons.ToolbarDecorator.Import);
// openButton.setToolTipText("Open");
// openButton.setPreferredSize(new Dimension(AllIcons.ToolbarDecorator.Import.getIconWidth() + 10, AllIcons.ToolbarDecorator.Import.getIconHeight() + 10));
// openButton.setBorderPainted(false);
// openButton.addActionListener(e -> {
// var descriptor = new FileChooserDescriptor(
// true, // Choose Files
// false,
// false,
// false,
// false,
// false
// );
// VirtualFile file = FileChooser.chooseFile(descriptor, null, null);
// if (file != null) {
// var str = Messages.showInputDialog("Enter Alias for " + file.getName(), "Alias for Imported Certificate", null);
// LoggerFactory.getLogger(JKSView.class).info("Selected file: alias {} {}", str, file.getPath());
// this.listModel.addElement(str);
// }
// });
// gbc.gridx = 0;
// gbc.gridy = 0;
// panel.add(openButton, gbc);
// JButton saveButton = new JButton(AllIcons.ToolbarDecorator.Export);
// saveButton.setPreferredSize(new Dimension(AllIcons.ToolbarDecorator.Export.getIconWidth() + 10, AllIcons.ToolbarDecorator.Export.getIconHeight() + 10));
// saveButton.setToolTipText("Save");
// saveButton.addActionListener(e -> {
// });
// gbc.gridx = 1;
// panel.add(saveButton, gbc);
//
// return panel;

}

private void updateView(Map<String, X509Certificate> certs) {
private void addCertificate(Map<String, X509Certificate> certs) {
certs.keySet().forEach(listModel::addElement);
list = new JBList<>(listModel);
list.setCellRenderer(new IconListRenderer());
Expand All @@ -223,8 +188,6 @@ private void updateView(Map<String, X509Certificate> certs) {
});
listPanel.removeAll();
listPanel.add(new JScrollPane(list), BorderLayout.CENTER);
// revalidate();
// repaint();
}

public @Nullable JComponent getUnlockText() {
Expand All @@ -239,4 +202,18 @@ 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);
}
}
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;
}
}
75 changes: 75 additions & 0 deletions src/main/java/com/jmpeax/ssltoolbox/jks/actions/ExportCert.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.ui.Messages;
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) {

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 descriptor = new FileSaverDescriptor("Export Certificate", "Export certificate", "cer");

var pwd = Messages.showPasswordDialog("Keystore password", "KeyStore Password");
if (pwd != null && !pwd.isBlank()) {
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");
}
}

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;
}
}
39 changes: 30 additions & 9 deletions src/main/java/com/jmpeax/ssltoolbox/jks/actions/ImportCert.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
package com.jmpeax.ssltoolbox.jks.actions;

import com.intellij.icons.AllIcons;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.diagnostic.Logger;
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 ImportCert extends AnAction {

private static final Logger LOGGER = Logger.getInstance(ImportCert.class);

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
try {
var f = e.getData(CommonDataKeys.VIRTUAL_FILE);
if (f == null) {
LOGGER.warn("JKS not send to the Action");
var certificateHelper = ApplicationManager.getApplication().getService(CertificateHelper.class);
var ksVirtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
if (ksVirtualFile == null) {
Messages.showErrorDialog("No Keystore file", "No Keystore File");
return;
}
var descriptor = new FileChooserDescriptor(
Expand All @@ -36,16 +39,34 @@ public void actionPerformed(@NotNull AnActionEvent e) {
);
VirtualFile file = FileChooser.chooseFile(descriptor, null, null);
if (file == null) {
LOGGER.warn("User did not select a certificate");
Messages.showErrorDialog("No certificate selected", "No Certificate Selected");
return;
}
var certAlias = certificateHelper.getCertificate(file)
.stream().findFirst().map(certificateHelper::getCommonName).orElse("");
var selectedAlias = new PrefillInputDialog(certAlias, "Certificate Alias", "Certificate Alias");
var ok = selectedAlias.showAndGet();
if (!ok) {
Messages.showErrorDialog("No alias provided", "No Alias Provided");
return;
}
Messages.showInputDialog("Cert alias","Certificate Alias", Messages.getQuestionIcon());
var pwd = Messages.showPasswordDialog("Keystore password", "KeyStore Password");
if (pwd != null && !pwd.isBlank()) {
CertificateHelper.importCertificate(f.getInputStream(), file.getInputStream(), pwd.toCharArray());
certificateHelper.importCertificate(ksVirtualFile, file,selectedAlias.getInput(), pwd.toCharArray());
Messages.showInfoMessage("Certificate imported", "Certificate Imported");
Objects.requireNonNull(getViewComponent(e)).addCertificate(selectedAlias.getInput(),
certificateHelper.getCertificate(file).stream().findFirst().orElseThrow());
}

} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.jmpeax.ssltoolbox.jks.actions;

import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.security.cert.X509Certificate;

public class ListenerDataContext implements DataContext {
private final VirtualFile file;
private final OnImport onImport;

public ListenerDataContext(VirtualFile file,OnImport onImport) {
this.file = file;
this.onImport = onImport;
}

@Override
public @Nullable Object getData(@NotNull String dataId) {
return file;
}

@Override
public <T> @Nullable T getData(@NotNull DataKey<T> key) {
return DataContext.super.getData(key);
}

public void update(String alias, X509Certificate certificate){
onImport.imported(alias,certificate);
}

interface OnImport {
void imported(String alias, X509Certificate cert);
}
}
Loading

0 comments on commit 4a87c52

Please sign in to comment.