| /******************************************************************************* |
| * Copyright (c) 2008, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Fabian Steeg <steeg@hbz-nrw.de> - Bug 474099 - Require certificate selection to confirm dialog |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.p2.ui.dialogs; |
| |
| import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; |
| |
| import java.io.*; |
| import java.security.cert.*; |
| import java.time.Instant; |
| import java.time.temporal.ChronoUnit; |
| import java.util.*; |
| import java.util.List; |
| import java.util.function.Function; |
| import java.util.stream.Collectors; |
| import org.bouncycastle.bcpg.ArmoredOutputStream; |
| import org.bouncycastle.openpgp.PGPPublicKey; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.ui.*; |
| import org.eclipse.equinox.internal.p2.ui.viewers.CertificateLabelProvider; |
| import org.eclipse.equinox.internal.provisional.security.ui.X500PrincipalHelper; |
| import org.eclipse.equinox.internal.provisional.security.ui.X509CertificateViewDialog; |
| import org.eclipse.equinox.p2.metadata.IArtifactKey; |
| import org.eclipse.equinox.p2.repository.spi.PGPPublicKeyService; |
| import org.eclipse.jface.dialogs.*; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.layout.TableColumnLayout; |
| import org.eclipse.jface.util.Policy; |
| import org.eclipse.jface.viewers.*; |
| import org.eclipse.jface.widgets.LabelFactory; |
| import org.eclipse.jface.widgets.WidgetFactory; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.SashForm; |
| import org.eclipse.swt.dnd.*; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| import org.eclipse.swt.layout.*; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.dialogs.SelectionDialog; |
| |
| /** |
| * A dialog that displays a certificate chain and asks the user if they trust |
| * the certificate providers. It also supports prompting about unsigned content. |
| */ |
| public class TrustCertificateDialog extends SelectionDialog { |
| private static final String EXPORT_FILTER_PATH = "exportFilterPath"; //$NON-NLS-1$ |
| |
| private CheckboxTableViewer certifcateViewer; |
| |
| private TreeViewer certificateChainViewer; |
| |
| private CheckboxTableViewer artifactViewer; |
| |
| private Button detailsButton; |
| |
| private Button exportButton; |
| |
| private final Map<TreeNode, List<IArtifactKey>> artifactMap = new LinkedHashMap<>(); |
| |
| public TrustCertificateDialog(Shell parentShell, Object input) { |
| super(parentShell); |
| |
| setShellStyle(SWT.DIALOG_TRIM | SWT.MODELESS | SWT.RESIZE | SWT.MAX | getDefaultOrientation()); |
| |
| if (input instanceof TreeNode[]) { |
| for (TreeNode node : (TreeNode[]) input) { |
| IArtifactKey[] associatedArtifacts = null; |
| if (node instanceof IAdaptable) { |
| associatedArtifacts = ((IAdaptable) node).getAdapter(IArtifactKey[].class); |
| } |
| artifactMap.put(node, associatedArtifacts == null ? List.of() : Arrays.asList(associatedArtifacts)); |
| } |
| } |
| |
| setTitle(ProvUIMessages.TrustCertificateDialog_Title); |
| |
| boolean unsignedContent = artifactMap.keySet().stream().map(TreeNode::getValue).anyMatch(Objects::isNull); |
| boolean pgpContent = containsInstance(input, PGPPublicKey.class); |
| boolean certifcateContent = containsInstance(input, Certificate.class); |
| |
| List<String> messages = new ArrayList<>(); |
| if (certifcateContent || pgpContent) { |
| messages.add(ProvUIMessages.TrustCertificateDialog_Message); |
| } |
| if (unsignedContent) { |
| messages.add(ProvUIMessages.TrustCertificateDialog_MessageUnsigned); |
| } |
| if (certifcateContent || pgpContent) { |
| messages.add(ProvUIMessages.TrustCertificateDialog_MessageNameWarning); |
| } |
| if (pgpContent) { |
| messages.add(ProvUIMessages.TrustCertificateDialog_MessagePGP); |
| } |
| setMessage(String.join(" ", messages)); //$NON-NLS-1$ |
| |
| if (PlatformUI.isWorkbenchRunning()) { |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(parentShell, IProvHelpContextIds.TRUST_DIALOG); |
| } |
| } |
| |
| public TreeViewer getCertificateChainViewer() { |
| return certificateChainViewer; |
| } |
| |
| @Override |
| protected Label createMessageArea(Composite composite) { |
| // Ensure that the message support wrapping for a long text message. |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); |
| data.widthHint = convertWidthInCharsToPixels(120); |
| LabelFactory factory = WidgetFactory.label(SWT.WRAP).font(composite.getFont()).layoutData(data); |
| if (getMessage() != null) { |
| factory.text(getMessage()); |
| } |
| return factory.create(composite); |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| Composite mainComposite = (Composite) super.createDialogArea(parent); |
| Dialog.applyDialogFont(mainComposite); |
| initializeDialogUnits(mainComposite); |
| |
| createMessageArea(mainComposite); |
| |
| SashForm sashForm = new SashForm(mainComposite, SWT.VERTICAL); |
| sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| |
| createCertificateViewerArea(createSashFormArea(sashForm)); |
| |
| // Create this area only if we have keys or certificates. |
| boolean containsCertificates = containsInstance(artifactMap.keySet(), PGPPublicKey.class) |
| || containsInstance(artifactMap.keySet(), Certificate.class); |
| if (containsCertificates) { |
| createCertficateChainViewerArea(createSashFormArea(sashForm)); |
| } |
| |
| // Sort the set of all artifacts and create the lower area only if there are |
| // artifacts. |
| Comparator<Object> comparator = Policy.getComparator(); |
| Set<IArtifactKey> artifacts = artifactMap.values().stream().flatMap(Collection::stream) |
| .collect(Collectors.toCollection(() -> new TreeSet<>((a1, a2) -> { |
| int result = comparator.compare(a1.getId(), a2.getId()); |
| if (result == 0) { |
| result = a1.getVersion().compareTo(a2.getVersion()); |
| if (result == 0) { |
| result = a1.getClassifier().compareTo(a2.getClassifier()); |
| } |
| } |
| return result; |
| }))); |
| if (!artifacts.isEmpty()) { |
| crreateArtifactViewerArea(createSashFormArea(sashForm), artifacts); |
| } |
| |
| // Set weights based on the children's preferred size. |
| Control[] children = sashForm.getChildren(); |
| int[] weights = new int[children.length]; |
| for (int i = 0; i < children.length; ++i) { |
| weights[i] = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, false).y; |
| } |
| sashForm.setWeights(weights); |
| |
| if (!getInitialElementSelections().isEmpty()) { |
| checkInitialSelections(); |
| } |
| |
| if (!artifactMap.isEmpty()) { |
| certifcateViewer.setSelection(new StructuredSelection(artifactMap.keySet().iterator().next())); |
| } |
| |
| return mainComposite; |
| } |
| |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| createButton(parent, IDialogConstants.OK_ID, ProvUIMessages.TrustCertificateDialog_AcceptSelectedButtonLabel, |
| true); |
| createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); |
| updateOkButton(); |
| } |
| |
| private void createButtons(Composite composite) { |
| Composite buttonComposite = new Composite(composite, SWT.NONE); |
| buttonComposite.setLayout(new RowLayout()); |
| |
| detailsButton = new Button(buttonComposite, SWT.NONE); |
| detailsButton.setText(ProvUIMessages.TrustCertificateDialog_Details); |
| detailsButton.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| X509Certificate cert = getInstance(certificateChainViewer.getSelection(), X509Certificate.class); |
| if (cert != null) { |
| X509CertificateViewDialog certificateDialog = new X509CertificateViewDialog(getShell(), cert); |
| certificateDialog.open(); |
| } |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| widgetDefaultSelected(e); |
| } |
| }); |
| |
| exportButton = new Button(buttonComposite, SWT.NONE); |
| exportButton.setText(ProvUIMessages.TrustCertificateDialog_Export); |
| exportButton.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| ISelection selection = certificateChainViewer.getSelection(); |
| X509Certificate cert = getInstance(selection, X509Certificate.class); |
| PGPPublicKey key = getInstance(selection, PGPPublicKey.class); |
| if (cert != null || key != null) { |
| FileDialog destination = new FileDialog(exportButton.getShell(), SWT.SAVE); |
| destination.setFilterPath(getFilterPath(EXPORT_FILTER_PATH)); |
| destination.setText(ProvUIMessages.TrustCertificateDialog_Export); |
| if (cert != null) { |
| destination.setFilterExtensions(new String[] { "*.der" }); //$NON-NLS-1$ |
| destination.setFileName(cert.getSerialNumber().toString() + ".der"); //$NON-NLS-1$ |
| String path = destination.open(); |
| setFilterPath(EXPORT_FILTER_PATH, destination.getFilterPath()); |
| if (path == null) { |
| return; |
| } |
| File destinationFile = new File(path); |
| try (FileOutputStream output = new FileOutputStream(destinationFile)) { |
| output.write(cert.getEncoded()); |
| } catch (IOException | CertificateEncodingException ex) { |
| ProvUIActivator.getDefault().getLog() |
| .log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, ex.getMessage(), ex)); |
| } |
| } else { |
| destination.setFilterExtensions(new String[] { "*.asc" }); //$NON-NLS-1$ |
| destination.setFileName(userFriendlyFingerPrint(key).replace(" ", "") + ".asc"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| String path = destination.open(); |
| setFilterPath(EXPORT_FILTER_PATH, destination.getFilterPath()); |
| if (path == null) { |
| return; |
| } |
| File destinationFile = new File(path); |
| try (OutputStream output = new ArmoredOutputStream(new FileOutputStream(destinationFile))) { |
| key.encode(output); |
| } catch (IOException ex) { |
| ProvUIActivator.getDefault().getLog() |
| .log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, ex.getMessage(), ex)); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| widgetDefaultSelected(e); |
| } |
| }); |
| } |
| |
| private Composite createSashFormArea(SashForm sashForm) { |
| Composite composite = new Composite(sashForm, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); |
| layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); |
| composite.setLayout(layout); |
| return composite; |
| } |
| |
| private void createCertificateViewerArea(Composite composite) { |
| |
| TableColumnLayout tableColumnLayout = new TableColumnLayout(true); |
| Composite tableComposite = WidgetFactory.composite(SWT.NONE) |
| .layoutData(new GridData(SWT.FILL, SWT.FILL, true, true)).layout(tableColumnLayout).create(composite); |
| Table table = WidgetFactory |
| .table(SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK) |
| .headerVisible(true).linesVisible(true).font(composite.getFont()).create(tableComposite); |
| certifcateViewer = new CheckboxTableViewer(table); |
| certifcateViewer.setContentProvider(new TreeNodeContentProvider()); |
| |
| GridData data = new GridData(GridData.FILL_BOTH); |
| data.heightHint = convertHeightInCharsToPixels(Math.min(artifactMap.keySet().size() + 1, 6)) * 3 / 2; |
| data.widthHint = convertWidthInCharsToPixels(120); |
| tableComposite.setLayoutData(data); |
| |
| // This column is packed later. |
| TableViewerColumn typeColumn = createColumn(certifcateViewer, ProvUIMessages.TrustCertificateDialog_ObjectType, |
| new PGPOrX509ColumnLabelProvider(key -> "PGP", cert -> "x509", //$NON-NLS-1$ //$NON-NLS-2$ |
| ProvUIMessages.TrustCertificateDialog_Unsigned), |
| tableColumnLayout, 1); |
| |
| createColumn(certifcateViewer, ProvUIMessages.TrustCertificateDialog_Id, |
| new PGPOrX509ColumnLabelProvider(TrustCertificateDialog::userFriendlyFingerPrint, |
| cert -> cert.getSerialNumber().toString(), ProvUIMessages.TrustCertificateDialog_NotApplicable), |
| tableColumnLayout, 10); |
| |
| createColumn(certifcateViewer, ProvUIMessages.TrustCertificateDialog_Name, |
| new PGPOrX509ColumnLabelProvider(pgp -> { |
| java.util.List<String> users = new ArrayList<>(); |
| pgp.getUserIDs().forEachRemaining(users::add); |
| return String.join(", ", users); //$NON-NLS-1$ |
| }, x509 -> { |
| X500PrincipalHelper principalHelper = new X500PrincipalHelper(x509.getSubjectX500Principal()); |
| return principalHelper.getCN() + "; " + principalHelper.getOU() + "; " //$NON-NLS-1$ //$NON-NLS-2$ |
| + principalHelper.getO(); |
| }, ProvUIMessages.TrustCertificateDialog_Unknown), tableColumnLayout, 15); |
| |
| createColumn(certifcateViewer, ProvUIMessages.TrustCertificateDialog_dates, |
| new PGPOrX509ColumnLabelProvider(pgp -> { |
| if (pgp.getCreationTime().after(Date.from(Instant.now()))) { |
| return NLS.bind(ProvUIMessages.TrustCertificateDialog_NotYetValidStartDate, |
| pgp.getCreationTime()); |
| } |
| long validSeconds = pgp.getValidSeconds(); |
| if (validSeconds == 0) { |
| return ProvUIMessages.TrustCertificateDialog_valid; |
| } |
| Instant expires = pgp.getCreationTime().toInstant().plus(validSeconds, ChronoUnit.SECONDS); |
| return expires.isBefore(Instant.now()) |
| ? NLS.bind(ProvUIMessages.TrustCertificateDialog_expiredSince, expires) |
| : NLS.bind(ProvUIMessages.TrustCertificateDialog_validExpires, expires); |
| }, x509 -> { |
| try { |
| x509.checkValidity(); |
| return ProvUIMessages.TrustCertificateDialog_valid; |
| } catch (CertificateExpiredException expired) { |
| return ProvUIMessages.TrustCertificateDialog_expired; |
| } catch (CertificateNotYetValidException notYetValid) { |
| return ProvUIMessages.TrustCertificateDialog_notYetValid; |
| } |
| }, ProvUIMessages.TrustCertificateDialog_NotApplicable), tableColumnLayout, 10); |
| |
| createMenu(certifcateViewer); |
| |
| addSelectionButtons(composite); |
| |
| certifcateViewer.addDoubleClickListener(e -> { |
| StructuredSelection selection = (StructuredSelection) e.getSelection(); |
| X509Certificate cert = getInstance(selection, X509Certificate.class); |
| if (cert != null) { |
| // create and open dialog for certificate chain |
| X509CertificateViewDialog certificateViewDialog = new X509CertificateViewDialog(getShell(), cert); |
| certificateViewDialog.open(); |
| } |
| }); |
| |
| certifcateViewer.addSelectionChangedListener(e -> { |
| if (getCertificateChainViewer() != null) { |
| TreeNode treeNode = getInstance(e.getSelection(), TreeNode.class); |
| if (treeNode != null) { |
| getCertificateChainViewer().setInput(new TreeNode[] { treeNode }); |
| getCertificateChainViewer().setSelection(new StructuredSelection(treeNode)); |
| } else { |
| getCertificateChainViewer().setInput(new TreeNode[] {}); |
| } |
| } |
| |
| updateOkButton(); |
| }); |
| |
| certifcateViewer.setInput(artifactMap.keySet().toArray(TreeNode[]::new)); |
| |
| typeColumn.getColumn().pack(); |
| } |
| |
| private void createCertficateChainViewerArea(Composite composite) { |
| certificateChainViewer = new TreeViewer(composite, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); |
| GridData data = new GridData(GridData.FILL_BOTH); |
| int treeSize = artifactMap.keySet().stream().map(TrustCertificateDialog::computeTreeSize) |
| .max(Integer::compareTo).orElse(0); |
| data.heightHint = convertHeightInCharsToPixels(Math.min(treeSize, 5)); |
| data.widthHint = convertWidthInCharsToPixels(120); |
| certificateChainViewer.getTree().setLayoutData(data); |
| |
| certificateChainViewer.setAutoExpandLevel(3); |
| certificateChainViewer.setContentProvider(new TreeNodeContentProvider()); |
| certificateChainViewer.setLabelProvider(new CertificateLabelProvider() { |
| @Override |
| public String getText(Object element) { |
| if (element instanceof TreeNode) { |
| Object o = ((TreeNode) element).getValue(); |
| if (o instanceof PGPPublicKey) { |
| PGPPublicKey key = (PGPPublicKey) o; |
| String userFriendlyFingerPrint = userFriendlyFingerPrint(key); |
| java.util.List<String> users = new ArrayList<>(); |
| key.getUserIDs().forEachRemaining(users::add); |
| String userIDs = String.join(", ", users); //$NON-NLS-1$ |
| if (!userIDs.isEmpty()) { |
| return userFriendlyFingerPrint + " [" + userIDs + "]"; //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| return userFriendlyFingerPrint; |
| } else if (o == null) { |
| return ProvUIMessages.TrustCertificateDialog_Unsigned; |
| } |
| } |
| |
| return super.getText(element); |
| } |
| }); |
| |
| certificateChainViewer.addSelectionChangedListener(event -> { |
| ISelection selection = event.getSelection(); |
| boolean containsCertificate = containsInstance(selection, X509Certificate.class); |
| detailsButton.setEnabled(containsCertificate); |
| exportButton.setEnabled(containsCertificate || containsInstance(selection, PGPPublicKey.class)); |
| }); |
| |
| createMenu(certificateChainViewer); |
| |
| createButtons(composite); |
| } |
| |
| private void crreateArtifactViewerArea(Composite composite, Set<IArtifactKey> artifacts) { |
| TableColumnLayout tableColumnLayout = new TableColumnLayout(true); |
| Composite tableComposite = WidgetFactory.composite(SWT.NONE) |
| .layoutData(new GridData(SWT.FILL, SWT.FILL, true, true)).layout(tableColumnLayout).create(composite); |
| Table table = WidgetFactory.table(SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION) |
| .headerVisible(true).linesVisible(true).font(composite.getFont()).create(tableComposite); |
| artifactViewer = new CheckboxTableViewer(table); |
| artifactViewer.setContentProvider(ArrayContentProvider.getInstance()); |
| |
| GridData data = new GridData(GridData.FILL_BOTH); |
| data.heightHint = convertHeightInCharsToPixels(Math.min(artifacts.size() + 1, 10)) * 3 / 2; |
| data.widthHint = convertWidthInCharsToPixels(120); |
| tableComposite.setLayoutData(data); |
| |
| Font font = table.getFont(); |
| FontData[] fontDatas = font.getFontData(); |
| for (FontData fontData : fontDatas) { |
| fontData.setStyle(fontData.getStyle() | SWT.BOLD); |
| } |
| Font boldFont = new Font(table.getDisplay(), fontDatas); |
| composite.addDisposeListener(e -> boldFont.dispose()); |
| |
| Function<IArtifactKey, Font> fontProvider = e -> { |
| for (Object object : certifcateViewer.getCheckedElements()) { |
| List<IArtifactKey> list = artifactMap.get(object); |
| if (list != null && list.contains(e)) { |
| return boldFont; |
| } |
| } |
| return null; |
| }; |
| |
| certifcateViewer.addCheckStateListener(e -> artifactViewer.refresh(true)); |
| |
| artifactViewer.addPostSelectionChangedListener(e -> { |
| if (table.isFocusControl()) { |
| List<?> selection = e.getStructuredSelection().toList(); |
| List<TreeNode> newSelection = new ArrayList<>(); |
| LOOP: for (Map.Entry<TreeNode, List<IArtifactKey>> entry : artifactMap.entrySet()) { |
| List<IArtifactKey> value = entry.getValue(); |
| if (value != null) { |
| for (IArtifactKey key : value) { |
| if (selection.contains(key)) { |
| newSelection.add(entry.getKey()); |
| continue LOOP; |
| } |
| } |
| } |
| } |
| |
| certifcateViewer.setSelection(new StructuredSelection(newSelection), true); |
| } |
| }); |
| |
| certifcateViewer.addPostSelectionChangedListener(e -> { |
| if (!table.isFocusControl()) { |
| Set<IArtifactKey> associatedArtifacts = new LinkedHashSet<>(); |
| for (Object object : e.getStructuredSelection()) { |
| List<IArtifactKey> list = artifactMap.get(object); |
| if (list != null) { |
| associatedArtifacts.addAll(list); |
| } |
| } |
| |
| artifactViewer.setSelection(new StructuredSelection(associatedArtifacts.toArray()), true); |
| |
| // Reorder the artifacts so that the selected ones are first. |
| LinkedHashSet<IArtifactKey> newInput = new LinkedHashSet<>(artifacts); |
| newInput.retainAll(associatedArtifacts); |
| newInput.addAll(artifacts); |
| artifactViewer.setInput(newInput); |
| |
| artifactViewer.setSelection(new StructuredSelection(associatedArtifacts.toArray()), true); |
| } |
| }); |
| |
| TableViewerColumn classifierColumn = createColumn(artifactViewer, |
| ProvUIMessages.TrustCertificateDialog_Classifier, |
| new ArtifactLabelProvider(a -> a.getClassifier(), fontProvider), tableColumnLayout, 1); |
| createColumn(artifactViewer, ProvUIMessages.TrustCertificateDialog_ArtifactId, |
| new ArtifactLabelProvider(a -> a.getId(), fontProvider), tableColumnLayout, 10); |
| createColumn(artifactViewer, ProvUIMessages.TrustCertificateDialog_Version, |
| new ArtifactLabelProvider(a -> a.getVersion().toString(), fontProvider), tableColumnLayout, 10); |
| |
| artifactViewer.setInput(artifacts); |
| |
| classifierColumn.getColumn().pack(); |
| } |
| |
| private void createMenu(StructuredViewer viewer) { |
| Control control = viewer.getControl(); |
| Menu menu = new Menu(control); |
| control.setMenu(menu); |
| MenuItem item = new MenuItem(menu, SWT.PUSH); |
| item.setText(ProvUIMessages.TrustCertificateDialog_CopyFingerprint); |
| item.addSelectionListener(widgetSelectedAdapter(e -> { |
| PGPPublicKey key = getInstance(viewer.getSelection(), PGPPublicKey.class); |
| if (key != null) { |
| Clipboard clipboard = new Clipboard(getShell().getDisplay()); |
| clipboard.setContents(new Object[] { userFriendlyFingerPrint(key) }, |
| new Transfer[] { TextTransfer.getInstance() }); |
| clipboard.dispose(); |
| } |
| })); |
| viewer.addSelectionChangedListener( |
| e -> item.setEnabled(containsInstance(e.getSelection(), PGPPublicKey.class))); |
| } |
| |
| private TableViewerColumn createColumn(TableViewer tableViewer, String text, ColumnLabelProvider labelProvider, |
| TableColumnLayout tableColumnLayout, int columnWeight) { |
| TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE); |
| column.getColumn().setText(text); |
| column.setLabelProvider(labelProvider); |
| tableColumnLayout.setColumnData(column.getColumn(), new ColumnWeightData(columnWeight)); |
| return column; |
| } |
| |
| /** |
| * Visually checks the previously-specified elements in this dialog's list |
| * viewer. |
| */ |
| private void checkInitialSelections() { |
| Iterator<?> itemsToCheck = getInitialElementSelections().iterator(); |
| while (itemsToCheck.hasNext()) { |
| certifcateViewer.setChecked(itemsToCheck.next(), true); |
| if (artifactViewer != null) { |
| artifactViewer.refresh(true); |
| } |
| } |
| } |
| |
| /** |
| * Add the selection and deselection buttons to the dialog. |
| * |
| * @param composite org.eclipse.swt.widgets.Composite |
| */ |
| private void addSelectionButtons(Composite composite) { |
| Composite buttonComposite = new Composite(composite, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 0; |
| layout.marginWidth = 0; |
| layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); |
| buttonComposite.setLayout(layout); |
| buttonComposite.setLayoutData(new GridData(SWT.END, SWT.TOP, true, false)); |
| |
| Button selectButton = createButton(buttonComposite, IDialogConstants.SELECT_ALL_ID, |
| ProvUIMessages.TrustCertificateDialog_SelectAll, false); |
| |
| SelectionListener listener = widgetSelectedAdapter(e -> { |
| certifcateViewer.setAllChecked(true); |
| if (artifactViewer != null) { |
| artifactViewer.refresh(true); |
| } |
| updateOkButton(); |
| }); |
| selectButton.addSelectionListener(listener); |
| |
| Button deselectButton = createButton(buttonComposite, IDialogConstants.DESELECT_ALL_ID, |
| ProvUIMessages.TrustCertificateDialog_DeselectAll, false); |
| |
| listener = widgetSelectedAdapter(e -> { |
| certifcateViewer.setAllChecked(false); |
| if (artifactViewer != null) { |
| artifactViewer.refresh(true); |
| } |
| updateOkButton(); |
| }); |
| deselectButton.addSelectionListener(listener); |
| } |
| |
| private String getFilterPath(String key) { |
| IDialogSettings dialogSettings = DialogSettings |
| .getOrCreateSection(ProvUIActivator.getDefault().getDialogSettings(), getClass().getName()); |
| String filterPath = dialogSettings.get(key); |
| if (filterPath == null) { |
| filterPath = System.getProperty("user.home"); //$NON-NLS-1$ |
| } |
| return filterPath; |
| } |
| |
| private void setFilterPath(String key, String filterPath) { |
| if (filterPath != null) { |
| IDialogSettings dialogSettings = DialogSettings |
| .getOrCreateSection(ProvUIActivator.getDefault().getDialogSettings(), getClass().getName()); |
| dialogSettings.put(key, filterPath); |
| } |
| } |
| |
| private void updateOkButton() { |
| Button okButton = getOkButton(); |
| if (okButton != null) { |
| certifcateViewer.getCheckedElements(); |
| Object[] checkedElements = certifcateViewer.getCheckedElements(); |
| Set<IArtifactKey> artifacts = artifactMap.values().stream().flatMap(Collection::stream) |
| .collect(Collectors.toSet()); |
| if (artifacts.isEmpty()) { |
| okButton.setEnabled(checkedElements.length > 0); |
| } else { |
| for (Object checkElement : checkedElements) { |
| artifacts.removeAll(artifactMap.get(checkElement)); |
| } |
| okButton.setEnabled(artifacts.isEmpty()); |
| } |
| } |
| } |
| |
| @Override |
| protected void okPressed() { |
| setResult(Arrays.asList(certifcateViewer.getCheckedElements())); |
| super.okPressed(); |
| } |
| |
| private static class PGPOrX509ColumnLabelProvider extends ColumnLabelProvider { |
| private Function<PGPPublicKey, String> pgpMap; |
| private Function<X509Certificate, String> x509map; |
| private String unsignedValue; |
| |
| public PGPOrX509ColumnLabelProvider(Function<PGPPublicKey, String> pgpMap, |
| Function<X509Certificate, String> x509map, String unsignedValue) { |
| this.pgpMap = pgpMap; |
| this.x509map = x509map; |
| this.unsignedValue = unsignedValue; |
| } |
| |
| @Override |
| public String getText(Object element) { |
| if (element instanceof TreeNode) { |
| element = ((TreeNode) element).getValue(); |
| } |
| if (element instanceof PGPPublicKey) { |
| return pgpMap.apply((PGPPublicKey) element); |
| } |
| if (element instanceof X509Certificate) { |
| return x509map.apply((X509Certificate) element); |
| } |
| |
| if (element == null) { |
| return unsignedValue; |
| } |
| return super.getText(element); |
| } |
| } |
| |
| private static class ArtifactLabelProvider extends ColumnLabelProvider { |
| private Function<IArtifactKey, String> labelProvider; |
| private Function<IArtifactKey, Font> fontProvider; |
| |
| public ArtifactLabelProvider(Function<IArtifactKey, String> labelProvider, |
| Function<IArtifactKey, Font> fontProvider) { |
| this.labelProvider = labelProvider; |
| this.fontProvider = fontProvider; |
| } |
| |
| @Override |
| public String getText(Object element) { |
| return labelProvider.apply((IArtifactKey) element); |
| } |
| |
| @Override |
| public Font getFont(Object element) { |
| return fontProvider.apply((IArtifactKey) element); |
| } |
| } |
| |
| private static int computeTreeSize(TreeNode node) { |
| int count = 1; |
| TreeNode[] children = node.getChildren(); |
| if (children != null) { |
| for (TreeNode child : children) { |
| count += computeTreeSize(child); |
| } |
| } |
| return count; |
| } |
| |
| private static <T> T getInstance(Object element, Class<T> type) { |
| if (type.isInstance(element)) { |
| return type.cast(element); |
| } else if (element instanceof Iterable) { |
| for (Object object : ((Iterable<?>) element)) { |
| T instance = getInstance(object, type); |
| if (instance != null) { |
| return instance; |
| } |
| } |
| } else if (element instanceof TreeNode) { |
| return getInstance(((TreeNode) element).getValue(), type); |
| } else if (element instanceof TreeNode[]) { |
| for (TreeNode child : (TreeNode[]) element) { |
| T instance = getInstance(child, type); |
| if (instance != null) { |
| return instance; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static boolean containsInstance(Object element, Class<?> type) { |
| return getInstance(element, type) != null; |
| } |
| |
| private static String userFriendlyFingerPrint(PGPPublicKey key) { |
| if (key == null) { |
| return null; |
| } |
| return PGPPublicKeyService.toHex(key.getFingerprint()).toUpperCase(Locale.ROOT); |
| } |
| } |