Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Merks2022-02-07 11:45:16 +0000
committerEd Merks2022-02-08 12:33:53 +0000
commitb6e71ef8ead586f8a94cea00c01392977f18338d (patch)
treed74c3b076ce4a1645e66e62628a319de7e94b567
parentff0f6eb56c4f5359f3cc0b01accd1e347d15ab5d (diff)
downloadrt.equinox.p2-b6e71ef8ead586f8a94cea00c01392977f18338d.tar.gz
rt.equinox.p2-b6e71ef8ead586f8a94cea00c01392977f18338d.tar.xz
rt.equinox.p2-b6e71ef8ead586f8a94cea00c01392977f18338d.zip
Bug 578024 - Improve the TrustCertificateDialogY20220209-0600I20220208-1800
Introduce org.eclipse.equinox.p2.repository.artifact.spi.IArtifactUIServices optionally implemented by UIServices implementations for enriched information that includes information about the artifacts associated with certificates and keys. Ensure that the new interface can delegate to older UIServices implementations. Upgrade CertificateChecker to compute the more detailed information and that it uses IArtifactUIServices when available, but also works properly when it's not available. Update ValidationDialogServiceUI so that it implements IArtifactUIServices and uses the enhanced information when available. Completely overhaul the TrustCertificateDialog implementation. Change-Id: I268bc7176af3eeb98b1d38a47b92d525f9b9f285 Signed-off-by: Ed Merks <ed.merks@gmail.com> Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/190518
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java159
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/spi/IArtifactUIServices.java96
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF1
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java10
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java155
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java816
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties14
8 files changed, 829 insertions, 425 deletions
diff --git a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
index d1e7137aa..561283093 100644
--- a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF
@@ -46,9 +46,10 @@ Import-Package: javax.xml.parsers,
org.eclipse.equinox.p2.query;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.artifact;version="[2.0.0,3.0.0)",
+ org.eclipse.equinox.p2.repository.artifact.spi;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.metadata;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.metadata.spi;version="[2.0.0,3.0.0)",
- org.eclipse.equinox.p2.repository.spi;version="2.0.0",
+ org.eclipse.equinox.p2.repository.spi;version="[2.0.0,3.0.0)",
org.eclipse.osgi.service.datalocation;version="1.0.0",
org.eclipse.osgi.service.debug;version="1.1.0",
org.eclipse.osgi.service.security;version="1.0.0",
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java
index e3b1265fb..4e68ef8e1 100644
--- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java
+++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java
@@ -33,7 +33,9 @@ import org.eclipse.equinox.p2.core.*;
import org.eclipse.equinox.p2.core.UIServices.TrustInfo;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.ProfileScope;
+import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
+import org.eclipse.equinox.p2.repository.artifact.spi.IArtifactUIServices;
import org.eclipse.equinox.p2.repository.spi.PGPPublicKeyService;
import org.eclipse.osgi.service.security.TrustEngine;
import org.eclipse.osgi.signedcontent.*;
@@ -90,7 +92,8 @@ public class CertificateChecker {
public IStatus start() {
final BundleContext context = EngineActivator.getContext();
- ServiceReference<SignedContentFactory> contentFactoryRef = context.getServiceReference(SignedContentFactory.class);
+ ServiceReference<SignedContentFactory> contentFactoryRef = context
+ .getServiceReference(SignedContentFactory.class);
SignedContentFactory verifierFactory = context.getService(contentFactoryRef);
try {
return checkCertificates(verifierFactory);
@@ -100,37 +103,43 @@ public class CertificateChecker {
}
private IStatus checkCertificates(SignedContentFactory verifierFactory) {
+ if (artifacts.isEmpty()) {
+ return Status.OK_STATUS;
+ }
+
UIServices serviceUI = agent.getService(UIServices.class);
- ArrayList<Certificate> untrustedCertificates = new ArrayList<>();
- Map<IArtifactDescriptor, Collection<PGPPublicKey>> untrustedPGPArtifacts = new HashMap<>();
- Map<IArtifactDescriptor, File> unsigned = new HashMap<>();
- ArrayList<Certificate[]> untrustedChain = new ArrayList<>();
- Map<Certificate, Collection<File>> untrustedArtifacts = new HashMap<>();
- IStatus status = Status.OK_STATUS;
- if (artifacts.isEmpty() || serviceUI == null) {
- return status;
+ if (serviceUI == null) {
+ return Status.OK_STATUS;
}
+
+ IArtifactUIServices artifactServiceUI = serviceUI instanceof IArtifactUIServices
+ ? (IArtifactUIServices) serviceUI
+ : (untrustedCertificateChains, untrustedPGPKeys, unsignedArtifacts,
+ artifactFiles) -> IArtifactUIServices.getTrustInfo(serviceUI, untrustedCertificateChains,
+ untrustedPGPKeys, unsignedArtifacts, artifactFiles);
+
+ Map<List<Certificate>, Set<IArtifactKey>> untrustedCertificates = new LinkedHashMap<>();
+ Map<PGPPublicKey, Set<IArtifactKey>> untrustedPGPKeys = new LinkedHashMap<>();
+ Set<IArtifactKey> unsignedArtifacts = new LinkedHashSet<>();
Set<PGPPublicKey> trustedKeySet = new HashSet<>();
boolean isTrustedKeySetInitialized = false;
+ Map<IArtifactKey, File> artifactFiles = new LinkedHashMap<>();
for (Entry<IArtifactDescriptor, File> artifact : artifacts.entrySet()) {
+ IArtifactDescriptor artifactDescriptor = artifact.getKey();
+ IArtifactKey artifactKey = artifactDescriptor.getArtifactKey();
File artifactFile = artifact.getValue();
+ artifactFiles.put(artifactKey, artifactFile);
try {
SignedContent content = verifierFactory.getSignedContent(artifactFile);
if (content.isSigned()) {
SignerInfo[] signerInfo = content.getSignerInfos();
+ // Only record the untrusted elements if there are no trusted elements.
if (Arrays.stream(signerInfo).noneMatch(SignerInfo::isTrusted)) {
- // Only record the untrusted elements if there are no trusted elements.
for (SignerInfo element : signerInfo) {
if (!element.isTrusted()) {
- Certificate[] certificateChain = element.getCertificateChain();
- if (!untrustedCertificates.contains(certificateChain[0])) {
- untrustedCertificates.add(certificateChain[0]);
- untrustedChain.add(certificateChain);
- }
- if (DebugHelper.DEBUG_CERTIFICATE_CHECKER_UNTRUSTED) {
- untrustedArtifacts.computeIfAbsent(certificateChain[0], key -> new ArrayList<>())
- .add(artifactFile);
- }
+ List<Certificate> certificateChain = Arrays.asList(element.getCertificateChain());
+ untrustedCertificates.computeIfAbsent(certificateChain, key -> new LinkedHashSet<>())
+ .add(artifactKey);
}
}
}
@@ -139,32 +148,36 @@ public class CertificateChecker {
// PGPSignatureVerifier verified the signatures against these keys.
List<PGPPublicKey> verifiedKeys = PGPPublicKeyStore
.readPublicKeys(
- artifact.getKey().getProperty(PGPSignatureVerifier.PGP_SIGNER_KEYS_PROPERTY_NAME))
+ artifactDescriptor.getProperty(PGPSignatureVerifier.PGP_SIGNER_KEYS_PROPERTY_NAME))
.stream().map(keyService::addKey).collect(Collectors.toList());
if (!verifiedKeys.isEmpty()) {
if (!isTrustedKeySetInitialized) {
isTrustedKeySetInitialized = true;
trustedKeySet.addAll(trustedKeys.get().all());
}
+ // Only record the untrusted keys if none of the keys are trusted.
if (verifiedKeys.stream().noneMatch(trustedKeySet::contains)) {
- untrustedPGPArtifacts.put(artifact.getKey(), verifiedKeys);
+ verifiedKeys
+ .forEach(key -> untrustedPGPKeys.computeIfAbsent(key, k -> new LinkedHashSet<>())
+ .add(artifactKey));
}
} else {
- unsigned.put(artifact.getKey(), artifactFile);
+ unsignedArtifacts.add(artifactKey);
}
}
} catch (GeneralSecurityException e) {
return new Status(IStatus.ERROR, EngineActivator.ID, Messages.CertificateChecker_SignedContentError, e);
} catch (IOException e) {
- return new Status(IStatus.ERROR, EngineActivator.ID, Messages.CertificateChecker_SignedContentIOError, e);
+ return new Status(IStatus.ERROR, EngineActivator.ID, Messages.CertificateChecker_SignedContentIOError,
+ e);
}
}
// log the unsigned artifacts if requested
- if (DebugHelper.DEBUG_CERTIFICATE_CHECKER_UNSIGNED && !unsigned.isEmpty()) {
+ if (DebugHelper.DEBUG_CERTIFICATE_CHECKER_UNSIGNED && !unsignedArtifacts.isEmpty()) {
StringBuilder message = new StringBuilder("The following artifacts are unsigned:\n"); //$NON-NLS-1$
- for (File file : unsigned.values()) {
- message.append(NLS.bind(" {0}\n", file.getPath())); //$NON-NLS-1$
+ for (IArtifactKey key : unsignedArtifacts) {
+ message.append(NLS.bind(" {0}\n", artifactFiles.get(key).getPath())); //$NON-NLS-1$
}
DebugHelper.debug(DEBUG_PREFIX, message.toString());
}
@@ -172,79 +185,75 @@ public class CertificateChecker {
// log the untrusted certificates if requested
if (DebugHelper.DEBUG_CERTIFICATE_CHECKER_UNTRUSTED && !untrustedCertificates.isEmpty()) {
StringBuilder message = new StringBuilder("The following certificates are untrusted:\n"); //$NON-NLS-1$
- for (Certificate cert : untrustedArtifacts.keySet()) {
- message.append(cert.toString() + "\n"); //$NON-NLS-1$
+ for (Map.Entry<List<Certificate>, Set<IArtifactKey>> entry : untrustedCertificates.entrySet()) {
+ message.append(entry.getKey().get(0).toString() + "\n"); //$NON-NLS-1$
message.append(" used by the following artifacts:\n"); //$NON-NLS-1$
- for (File file : untrustedArtifacts.get(cert)) {
- message.append(NLS.bind(" {0}\n", file.getPath())); //$NON-NLS-1$
+ for (IArtifactKey key : entry.getValue()) {
+ message.append(NLS.bind(" {0}\n", artifactFiles.get(key).getPath())); //$NON-NLS-1$
}
+
}
DebugHelper.debug(DEBUG_PREFIX, message.toString());
}
- Set<PGPPublicKey> untrustedPGPKeys = untrustedPGPArtifacts.values().stream().flatMap(Collection::stream)
- .collect(Collectors.toSet());
+
if (DebugHelper.DEBUG_CERTIFICATE_CHECKER_UNTRUSTED && !untrustedPGPKeys.isEmpty()) {
StringBuilder message = new StringBuilder("The following PGP Keys are untrusted:\n"); //$NON-NLS-1$
- for (PGPPublicKey untrustedKey : untrustedPGPKeys) {
- message.append(Long.toHexString(untrustedKey.getKeyID()) + "\n"); //$NON-NLS-1$
+ for (Map.Entry<PGPPublicKey, Set<IArtifactKey>> entry : untrustedPGPKeys.entrySet()) {
+ message.append(Long.toHexString(entry.getKey().getKeyID()) + "\n"); //$NON-NLS-1$
message.append(" used by the following artifacts:\n"); //$NON-NLS-1$
- for (Entry<IArtifactDescriptor, Collection<PGPPublicKey>> entry : untrustedPGPArtifacts.entrySet()) {
- if (entry.getValue().stream().anyMatch(signer -> signer.getKeyID() == untrustedKey.getKeyID())) {
- message.append(NLS.bind(" {0}\n", entry.getKey().getArtifactKey())); //$NON-NLS-1$
- }
+ for (IArtifactKey key : entry.getValue()) {
+ message.append(NLS.bind(" {0}\n", key)); //$NON-NLS-1$
}
}
DebugHelper.debug(DEBUG_PREFIX, message.toString());
}
String policy = getUnsignedContentPolicy();
- //if there is unsigned content and we should never allow it, then fail without further checking certificates
- if (!unsigned.isEmpty() && EngineActivator.UNSIGNED_FAIL.equals(policy)) {
- return new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.CertificateChecker_UnsignedNotAllowed, unsigned));
+ // if there is unsigned content and we should never allow it, then fail without
+ // further checking certificates
+ if (!unsignedArtifacts.isEmpty() && EngineActivator.UNSIGNED_FAIL.equals(policy)) {
+ return new Status(IStatus.ERROR, EngineActivator.ID,
+ NLS.bind(Messages.CertificateChecker_UnsignedNotAllowed, unsignedArtifacts.stream()
+ .map(key -> artifactFiles.get(key)).collect(Collectors.toList())));
}
- String[] details = EngineActivator.UNSIGNED_ALLOW.equals(policy) || unsigned.isEmpty() ? null
- : unsigned.entrySet().stream().map(entry -> {
- String detail = entry.getValue().toString();
- if (untrustedPGPKeys != null && !untrustedPGPKeys.isEmpty()) {
- return detail + untrustedPGPKeys.stream().map(PGPPublicKey::getKeyID).map(Long::toHexString)
- .collect(Collectors.joining(", ", " [", "]")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- return detail;
- }).toArray(String[]::new);
- Certificate[][] unTrustedCertificateChains = untrustedCertificates.isEmpty() ? null
- : untrustedChain.toArray(Certificate[][]::new);
// If there was no unsigned content, and nothing untrusted, no need to prompt.
- if (details == null && unTrustedCertificateChains == null && untrustedPGPArtifacts.isEmpty()) {
- return status;
+ if ((EngineActivator.UNSIGNED_ALLOW.equals(policy) || unsignedArtifacts.isEmpty())
+ && untrustedCertificates.isEmpty() && untrustedPGPKeys.isEmpty()) {
+ return Status.OK_STATUS;
}
- TrustInfo trustInfo = serviceUI.getTrustInfo(unTrustedCertificateChains,
- untrustedPGPKeys,
- details);
+ TrustInfo trustInfo = artifactServiceUI.getTrustInfo(untrustedCertificates, untrustedPGPKeys, unsignedArtifacts,
+ artifactFiles);
- // If user doesn't trust unsigned content, cancel the operation
- if (!unsigned.isEmpty() && !trustInfo.trustUnsignedContent()) {
+ // If there is unsigned content and user doesn't trust unsigned content, cancel
+ // the operation.
+ if (!unsignedArtifacts.isEmpty() && !trustInfo.trustUnsignedContent()) {
return Status.CANCEL_STATUS;
}
Certificate[] trustedCertificates = trustInfo.getTrustedCertificates();
// If we had untrusted chains and nothing was trusted, cancel the operation
- if (unTrustedCertificateChains != null && trustedCertificates == null) {
+ if (!untrustedCertificates.isEmpty() && trustedCertificates == null) {
return new Status(IStatus.CANCEL, EngineActivator.ID, Messages.CertificateChecker_CertificateRejected);
}
+
// Anything that was trusted should be removed from the untrusted list
if (trustedCertificates != null) {
- for (Certificate trustedCertificate : trustedCertificates) {
- untrustedCertificates.remove(trustedCertificate);
- }
+ List<Certificate> trustedCertificateList = Arrays.asList(trustedCertificates);
+ untrustedCertificates.keySet().removeIf(it -> trustedCertificateList.contains(it.get(0)));
}
trustedKeySet.addAll(trustInfo.getTrustedPGPKeys());
- untrustedPGPArtifacts.values().removeIf(pgpKeys -> pgpKeys.stream().anyMatch(trustedKeySet::contains));
+
+ Set<IArtifactKey> trustedArtifactKeys = trustedKeySet.stream().map(untrustedPGPKeys::get)
+ .filter(Objects::nonNull).flatMap(Set::stream)
+ .collect(Collectors.toSet());
+ untrustedPGPKeys.values().forEach(it -> it.removeAll(trustedArtifactKeys));
+ untrustedPGPKeys.values().removeIf(Collection::isEmpty);
// If there is still untrusted content, cancel the operation
- if (!untrustedCertificates.isEmpty() || !untrustedPGPArtifacts.isEmpty()) {
+ if (!untrustedCertificates.isEmpty() || !untrustedPGPKeys.isEmpty()) {
return new Status(IStatus.CANCEL, EngineActivator.ID, Messages.CertificateChecker_CertificateRejected);
}
// If we should persist the trusted certificates, add them to the trust engine
@@ -263,14 +272,16 @@ public class CertificateChecker {
pgpStatus.getMessage() + '\n' + certifactesStatus.getMessage(), null);
}
- return status;
+ return Status.OK_STATUS;
}
private IStatus persistTrustedCertificates(Certificate[] trustedCertificates) {
if (trustedCertificates == null)
- // I'm pretty sure this would be a bug; trustedCertificates should never be null here.
+ // I'm pretty sure this would be a bug; trustedCertificates should never be null
+ // here.
return new Status(IStatus.INFO, EngineActivator.ID, Messages.CertificateChecker_CertificateRejected);
- ServiceTracker<TrustEngine, TrustEngine> trustEngineTracker = new ServiceTracker<>(EngineActivator.getContext(), TrustEngine.class, null);
+ ServiceTracker<TrustEngine, TrustEngine> trustEngineTracker = new ServiceTracker<>(EngineActivator.getContext(),
+ TrustEngine.class, null);
trustEngineTracker.open();
Object[] trustEngines = trustEngineTracker.getServices();
try {
@@ -283,13 +294,16 @@ public class CertificateChecker {
continue;
try {
trustEngine.addTrustAnchor(trustedCertificate, trustedCertificate.toString());
- // this should mean we added an anchor successfully; continue to next certificate
+ // this should mean we added an anchor successfully; continue to next
+ // certificate
break;
} catch (IOException e) {
- //just return an INFO so the user can proceed with the install
- return new Status(IStatus.INFO, EngineActivator.ID, Messages.CertificateChecker_KeystoreConnectionError, e);
+ // just return an INFO so the user can proceed with the install
+ return new Status(IStatus.INFO, EngineActivator.ID,
+ Messages.CertificateChecker_KeystoreConnectionError, e);
} catch (GeneralSecurityException e) {
- return new Status(IStatus.INFO, EngineActivator.ID, Messages.CertificateChecker_CertificateError, e);
+ return new Status(IStatus.INFO, EngineActivator.ID,
+ Messages.CertificateChecker_CertificateError, e);
}
}
}
@@ -377,4 +391,3 @@ public class CertificateChecker {
return Status.OK_STATUS;
}
}
-
diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/spi/IArtifactUIServices.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/spi/IArtifactUIServices.java
new file mode 100644
index 000000000..b5cc328f5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/p2/repository/artifact/spi/IArtifactUIServices.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Eclipse contributors 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
+ *******************************************************************************/
+package org.eclipse.equinox.p2.repository.artifact.spi;
+
+import java.io.File;
+import java.security.cert.Certificate;
+import java.util.*;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.eclipse.equinox.p2.core.UIServices;
+import org.eclipse.equinox.p2.core.UIServices.TrustInfo;
+import org.eclipse.equinox.p2.metadata.IArtifactKey;
+
+/**
+ * An interface optionally implemented by {@link UIServices} to provide richer
+ * information for the users. In particular, the users often wish to know which
+ * artifacts are signed by which certificates or which keys when they are
+ * {@link UIServices#getTrustInfo(Certificate[][], Collection, String[])
+ * prompted} whether to trust such certificates or keys.
+ *
+ * @since 2.6
+ *
+ * @see UIServices#getTrustInfo(Certificate[][], Collection, String[])
+ */
+public interface IArtifactUIServices {
+
+ /**
+ * Opens a UI prompt to capture information about trusted content.
+ *
+ * @param untrustedCertificateChains a map from untrusted certificate chains to
+ * the set of keys of the artifacts signed by
+ * that chain.
+ * @param untrustedPGPKeys a map of untrusted PGP public keys to the
+ * set of keys of the artifacts signed by that
+ * key.
+ * @param unsignedArtifacts a set of keys of the artifacts that are not
+ * signed.
+ * @param artifactFiles a map from artifact keys to the file
+ * associated with that artifact key.
+ *
+ * @return the TrustInfo that describes the user's choices for trusting
+ * certificates, keys, and unsigned content.
+ *
+ * @see #getTrustInfo(UIServices, Map, Map, Set, Map)
+ * @see UIServices
+ */
+ TrustInfo getTrustInfo( //
+ Map<List<Certificate>, Set<IArtifactKey>> untrustedCertificateChains, //
+ Map<PGPPublicKey, Set<IArtifactKey>> untrustedPGPKeys, //
+ Set<IArtifactKey> unsignedArtifacts, //
+ Map<IArtifactKey, File> artifactFiles);
+
+ /**
+ * Opens a UI prompt to capture information about trusted content. This
+ * implementation is useful for delegating to an old-style
+ * {@link UIServices#getTrustInfo(Certificate[][], Collection, String[])
+ * UIServices implementation} that does not support the IArtifactUIServices
+ * interface.
+ *
+ * @param uiServices the delegate UI services.
+ * @param untrustedCertificateChains a map from untrusted certificate chains to
+ * the set of keys of the artifacts signed by
+ * that chain.
+ * @param untrustedPGPKeys a map of untrusted PGP public keys to the
+ * set of keys of the artifacts signed by that
+ * key.
+ * @param unsignedArtifacts a set of keys of the artifacts that are not
+ * signed.
+ * @param artifactFiles a map from artifact keys to the file
+ * associated with that artifact key.
+ *
+ * @return the TrustInfo that describes the user's choices for trusting
+ * certificates, keys, and unsigned content.
+ *
+ * @see #getTrustInfo(Map, Map, Set, Map)
+ * @see UIServices#getTrustInfo(Certificate[][], Collection, String[])
+ */
+ static TrustInfo getTrustInfo(UIServices uiServices, //
+ Map<List<Certificate>, Set<IArtifactKey>> untrustedCertificateChains, //
+ Map<PGPPublicKey, Set<IArtifactKey>> untrustedPGPKeys, //
+ Set<IArtifactKey> unsignedArtifacts, //
+ Map<IArtifactKey, File> artifactFiles) {
+ Certificate[][] unTrustedCertificateChainsArray = untrustedCertificateChains.keySet().stream()
+ .map(c -> c.toArray(Certificate[]::new)).toArray(Certificate[][]::new);
+ String[] details = unsignedArtifacts.isEmpty() ? null
+ : unsignedArtifacts.stream().map(artifactFiles::get).map(Objects::toString).toArray(String[]::new);
+ return uiServices.getTrustInfo(unTrustedCertificateChainsArray, untrustedPGPKeys.keySet(), details);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
index bbf2e9b30..27fe90a63 100644
--- a/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
@@ -61,6 +61,7 @@ Import-Package: javax.xml.parsers,
org.eclipse.equinox.p2.query;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.artifact;version="[2.0.0,3.0.0)",
+ org.eclipse.equinox.p2.repository.artifact.spi;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.metadata;version="[2.0.0,3.0.0)",
org.eclipse.equinox.p2.repository.spi;version="2.0.0",
org.osgi.framework;version="1.6.0",
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
index 0b293d381..e1c97a8c1 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ProvUIMessages.java
@@ -274,21 +274,29 @@ public class ProvUIMessages extends NLS {
public static String TrustCertificateDialog_Export;
public static String TrustCertificateDialog_Title;
public static String TrustCertificateDialog_Message;
- public static String TrustCertificateDialog_MessageWithPGP;
+ public static String TrustCertificateDialog_MessageUnsigned;
+ public static String TrustCertificateDialog_MessageNameWarning;
+ public static String TrustCertificateDialog_MessagePGP;
public static String TrustCertificateDialog_AcceptSelectedButtonLabel;
+ public static String TrustCertificateDialog_ArtifactId;
public static String TrustCertificateDialog_SelectAll;
public static String TrustCertificateDialog_DeselectAll;
public static String TrustCertificateDialog_ObjectType;
public static String TrustCertificateDialog_Id;
public static String TrustCertificateDialog_Name;
+ public static String TrustCertificateDialog_Classifier;
public static String TrustCertificateDialog_CopyFingerprint;
public static String TrustCertificateDialog_dates;
+ public static String TrustCertificateDialog_NotApplicable;
public static String TrustCertificateDialog_NotYetValidStartDate;
public static String TrustCertificateDialog_expiredSince;
public static String TrustCertificateDialog_validExpires;
public static String TrustCertificateDialog_valid;
public static String TrustCertificateDialog_expired;
public static String TrustCertificateDialog_notYetValid;
+ public static String TrustCertificateDialog_Unknown;
+ public static String TrustCertificateDialog_Unsigned;
+ public static String TrustCertificateDialog_Version;
// Operations
public static String UpdateManagerCompatibility_ExportSitesTitle;
public static String UpdateManagerCompatibility_ImportSitesTitle;
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
index 877f1550d..5e6e6f04d 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
@@ -14,10 +14,13 @@
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui;
+import java.io.File;
import java.net.URL;
import java.security.cert.Certificate;
import java.util.*;
import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
@@ -25,6 +28,8 @@ import org.eclipse.equinox.internal.p2.ui.dialogs.TrustCertificateDialog;
import org.eclipse.equinox.internal.p2.ui.dialogs.UserValidationDialog;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.UIServices;
+import org.eclipse.equinox.p2.metadata.IArtifactKey;
+import org.eclipse.equinox.p2.repository.artifact.spi.IArtifactUIServices;
import org.eclipse.equinox.p2.repository.spi.PGPPublicKeyService;
import org.eclipse.equinox.p2.ui.LoadMetadataRepositoryJob;
import org.eclipse.jface.dialogs.*;
@@ -42,7 +47,7 @@ import org.eclipse.ui.PlatformUI;
* declaration is made in the serviceui_component.xml file.
*
*/
-public class ValidationDialogServiceUI extends UIServices {
+public class ValidationDialogServiceUI extends UIServices implements IArtifactUIServices {
private final IProvisioningAgent agent;
@@ -181,56 +186,101 @@ public class ValidationDialogServiceUI extends UIServices {
// We've established trust for unsigned content, now examine the untrusted
// chains
if (!isHeadless() && (untrustedChains.length > 0 || !untrustedPublicKeys.isEmpty())) {
- final TrustCertificateDialog[] dialog = new TrustCertificateDialog[1];
- final TreeNode[] input = createTreeNodes(untrustedChains, untrustedPublicKeys);
- PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
- Shell shell = ProvUI.getDefaultParentShell();
- TrustCertificateDialog trustCertificateDialog = new TrustCertificateDialog(shell, input);
- dialog[0] = trustCertificateDialog;
- trustCertificateDialog.open();
- });
- persistTrust = true;
- if (dialog[0].getResult() != null) {
- for (Object o : dialog[0].getResult()) {
- if (o instanceof TreeNode) {
- o = ((TreeNode) o).getValue();
- }
- if (o instanceof Certificate) {
- trustedCertificates.add((Certificate) o);
- } else if (o instanceof PGPPublicKey) {
- trustedKeys.add((PGPPublicKey) o);
+ return getTrustInfo(
+ Arrays.stream(untrustedChains).collect(
+ Collectors.toMap(Arrays::asList, it -> Set.of(), (e1, e2) -> e1, LinkedHashMap::new)),
+ untrustedPublicKeys.stream().collect(
+ Collectors.toMap(Function.identity(), it -> Set.of(), (e1, e2) -> e1, LinkedHashMap::new)),
+ null, null);
+
+ }
+
+ return new TrustInfo(trustedCertificates, trustedKeys, persistTrust, trustUnsigned);
+ }
+
+ @Override
+ public TrustInfo getTrustInfo(Map<List<Certificate>, Set<IArtifactKey>> untrustedCertificates,
+ Map<PGPPublicKey, Set<IArtifactKey>> untrustedPGPKeys, //
+ Set<IArtifactKey> unsignedArtifacts, //
+ Map<IArtifactKey, File> artifacts) {
+ boolean trustUnsigned = true;
+ boolean persistTrust = false;
+ List<Certificate> trustedCertificates = new ArrayList<>();
+ List<PGPPublicKey> trustedKeys = new ArrayList<>();
+ if (!isHeadless()) {
+ TreeNode[] input = createTreeNodes(untrustedCertificates, untrustedPGPKeys, unsignedArtifacts, artifacts);
+ if (input.length != 0) {
+ trustUnsigned = unsignedArtifacts == null || unsignedArtifacts.isEmpty();
+ final TrustCertificateDialog[] dialog = new TrustCertificateDialog[1];
+ PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ Shell shell = ProvUI.getDefaultParentShell();
+ TrustCertificateDialog trustCertificateDialog = new TrustCertificateDialog(shell, input);
+ dialog[0] = trustCertificateDialog;
+ trustCertificateDialog.open();
+ });
+ persistTrust = true;
+ if (dialog[0].getResult() != null) {
+ for (Object o : dialog[0].getResult()) {
+ if (o instanceof TreeNode) {
+ o = ((TreeNode) o).getValue();
+ }
+ if (o instanceof Certificate) {
+ trustedCertificates.add((Certificate) o);
+ } else if (o instanceof PGPPublicKey) {
+ trustedKeys.add((PGPPublicKey) o);
+ } else if (o == null) {
+ trustUnsigned = true;
+ }
}
}
}
}
+
return new TrustInfo(trustedCertificates, trustedKeys, persistTrust, trustUnsigned);
}
- private TreeNode[] createTreeNodes(Certificate[][] certificates, Collection<PGPPublicKey> untrustedPublicKeys) {
- TreeNode[] children = new TreeNode[certificates.length + untrustedPublicKeys.size()];
- int i = 0;
- for (i = 0; i < certificates.length; i++) {
- TreeNode head = new TreeNode(certificates[i][0]);
- TreeNode parent = head;
- children[i] = head;
- for (int j = 0; j < certificates[i].length; j++) {
- TreeNode node = new TreeNode(certificates[i][j]);
- node.setParent(parent);
- parent.setChildren(new TreeNode[] { node });
- parent = node;
+ private TreeNode[] createTreeNodes(Map<List<Certificate>, Set<IArtifactKey>> untrustedCertificates,
+ Map<PGPPublicKey, Set<IArtifactKey>> untrustedPGPKeys, //
+ Set<IArtifactKey> unsignedArtifacts, //
+ Map<IArtifactKey, File> artifacts) {
+
+ List<ExtendedTreeNode> children = new ArrayList<>();
+ if (untrustedCertificates != null && !untrustedCertificates.isEmpty()) {
+ for (Map.Entry<List<Certificate>, Set<IArtifactKey>> entry : untrustedCertificates.entrySet()) {
+ ExtendedTreeNode parent = null;
+ List<Certificate> key = entry.getKey();
+ Set<IArtifactKey> associatedArtifacts = entry.getValue();
+ for (Certificate certificate : key) {
+ ExtendedTreeNode node = new ExtendedTreeNode(certificate, associatedArtifacts);
+ if (parent == null) {
+ children.add(node);
+ } else {
+ node.setParent(parent);
+ parent.setChildren(new TreeNode[] { node });
+ }
+ parent = node;
+ }
}
}
- if (!untrustedPublicKeys.isEmpty()) {
+ if (untrustedPGPKeys != null && !untrustedPGPKeys.isEmpty()) {
PGPPublicKeyService keyService = agent == null ? null : agent.getService(PGPPublicKeyService.class);
- for (PGPPublicKey key : untrustedPublicKeys) {
- TreeNode treeNode = new TreeNode(key);
- children[i] = treeNode;
- expandChildren(treeNode, key, keyService, new HashSet<>(), Integer.getInteger("p2.pgp.trust.depth", 3)); //$NON-NLS-1$
- i++;
+ for (Map.Entry<PGPPublicKey, Set<IArtifactKey>> entry : untrustedPGPKeys.entrySet()) {
+ PGPPublicKey key = entry.getKey();
+ Set<IArtifactKey> associatedArtifacts = entry.getValue();
+ ExtendedTreeNode node = new ExtendedTreeNode(key, associatedArtifacts);
+ children.add(node);
+ expandChildren(node, key, keyService, new HashSet<>(), Integer.getInteger("p2.pgp.trust.depth", 3)); //$NON-NLS-1$
}
}
- return children;
+
+ if (unsignedArtifacts != null && !unsignedArtifacts.isEmpty()) {
+ ExtendedTreeNode node = new ExtendedTreeNode(null, unsignedArtifacts);
+ children.add(node);
+
+ }
+
+ return children.toArray(TreeNode[]::new);
}
private void expandChildren(TreeNode result, PGPPublicKey key, PGPPublicKeyService keyService,
@@ -305,4 +355,33 @@ public class ValidationDialogServiceUI extends UIServices {
return !PlatformUI.isWorkbenchRunning();
}
+ private static class ExtendedTreeNode extends TreeNode implements IAdaptable {
+ private final Set<IArtifactKey> artifacts;
+
+ public ExtendedTreeNode(Object value) {
+ super(value);
+ artifacts = null;
+ }
+
+ public ExtendedTreeNode(Object value, Set<IArtifactKey> artifacts) {
+ super(value);
+ this.artifacts = artifacts;
+ }
+
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+ if (adapter.isInstance(this)) {
+ return adapter.cast(this);
+ }
+ if (adapter.isInstance(getValue())) {
+ return adapter.cast(value);
+ }
+ if (adapter == IArtifactKey[].class && artifacts != null) {
+ return adapter.cast(artifacts.toArray(IArtifactKey[]::new));
+ }
+
+ return null;
+ }
+ }
+
}
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
index a5d0d0769..9666a6113 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
@@ -21,19 +21,22 @@ 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.IStatus;
-import org.eclipse.core.runtime.Status;
+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.dialogs.IDialogConstants;
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;
@@ -43,6 +46,8 @@ 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;
@@ -50,148 +55,135 @@ import org.eclipse.ui.dialogs.SelectionDialog;
/**
* A dialog that displays a certificate chain and asks the user if they trust
- * the certificate providers.
+ * 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 Object inputElement;
- private IStructuredContentProvider contentProvider;
-
- CheckboxTableViewer listViewer;
+ private CheckboxTableViewer certifcateViewer;
private TreeViewer certificateChainViewer;
- protected TreeNode parentElement;
- protected Object selectedCertificate;
+
+ 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);
- inputElement = input;
- this.contentProvider = new TreeNodeContentProvider();
- setTitle(ProvUIMessages.TrustCertificateDialog_Title);
- setMessage(containsPGPKeys(inputElement) ? ProvUIMessages.TrustCertificateDialog_MessageWithPGP
- : ProvUIMessages.TrustCertificateDialog_Message);
- setShellStyle(SWT.DIALOG_TRIM | SWT.MODELESS | SWT.RESIZE | getDefaultOrientation());
- PlatformUI.getWorkbench().getHelpSystem().setHelp(parentShell, IProvHelpContextIds.TRUST_DIALOG);
- }
- private static boolean containsPGPKeys(Object inputElement) {
- if (inputElement instanceof PGPPublicKey) {
- return true;
- } else if (inputElement instanceof PGPPublicKey[]) {
- return ((PGPPublicKey[]) inputElement).length > 0;
- } else if (inputElement instanceof Iterable) {
- Iterator<?> iterator = ((Iterable<?>) inputElement).iterator();
- while (iterator.hasNext()) {
- if (containsPGPKeys(iterator.next())) {
- return true;
- }
- }
- } else if (inputElement instanceof TreeNode) {
- return containsPGPKeys(((TreeNode) inputElement).getValue());
- } else if (inputElement instanceof TreeNode[]) {
- for (TreeNode child : (TreeNode[]) inputElement) {
- if (containsPGPKeys(child)) {
- return true;
+ 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));
}
}
- return false;
- }
- private static class PGPOrX509ColumnLabelProvider extends ColumnLabelProvider {
- private Function<PGPPublicKey, String> pgpMap;
- private Function<X509Certificate, String> x509map;
+ setTitle(ProvUIMessages.TrustCertificateDialog_Title);
- public PGPOrX509ColumnLabelProvider(Function<PGPPublicKey, String> pgpMap,
- Function<X509Certificate, String> x509map) {
- this.pgpMap = pgpMap;
- this.x509map = x509map;
+ 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$
- @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);
- }
- return super.getText(element);
+ 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) {
- SashForm sashForm = createUpperDialogArea(parent);
- Composite composite = createSashFormArea(sashForm);
+ Composite mainComposite = (Composite) super.createDialogArea(parent);
+ Dialog.applyDialogFont(mainComposite);
+ initializeDialogUnits(mainComposite);
- certificateChainViewer = new TreeViewer(composite, SWT.BORDER);
- GridData data = new GridData(GridData.FILL_BOTH);
- data.grabExcessHorizontalSpace = true;
- data.heightHint = convertHeightInCharsToPixels(8);
- data.widthHint = convertWidthInCharsToPixels(120);
- certificateChainViewer.getTree().setLayoutData(data);
- certificateChainViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
- 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$
+ 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 userFriendlyFingerPrint;
}
- }
- return super.getText(element);
- }
- });
- certificateChainViewer.addSelectionChangedListener(getChainSelectionListener());
- Menu menu = new Menu(certificateChainViewer.getTree());
- certificateChainViewer.getTree().setMenu(menu);
- MenuItem item = new MenuItem(menu, SWT.PUSH);
- item.setText(ProvUIMessages.TrustCertificateDialog_CopyFingerprint);
- item.addSelectionListener(widgetSelectedAdapter(e -> {
- Object o = ((IStructuredSelection) certificateChainViewer.getSelection()).getFirstElement();
- if (o instanceof TreeNode) {
- o = ((TreeNode) o).getValue();
- }
- if (o instanceof PGPPublicKey) {
- PGPPublicKey key = (PGPPublicKey) o;
- Clipboard clipboard = new Clipboard(getShell().getDisplay());
- clipboard.setContents(new Object[] { userFriendlyFingerPrint(key) },
- new Transfer[] { TextTransfer.getInstance() });
- clipboard.dispose();
- }
- }));
- certificateChainViewer.addSelectionChangedListener(e -> item.setEnabled(containsPGPKeys(e.getSelection())));
+ return result;
+ })));
+ if (!artifacts.isEmpty()) {
+ crreateArtifactViewerArea(createSashFormArea(sashForm), artifacts);
+ }
- listViewer.addDoubleClickListener(getDoubleClickListener());
- listViewer.addSelectionChangedListener(getParentSelectionListener());
+ // 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);
- createButtons(composite);
+ if (!getInitialElementSelections().isEmpty()) {
+ checkInitialSelections();
+ }
- if (inputElement instanceof Object[]) {
- Object[] nodes = (Object[]) inputElement;
- if (nodes.length > 0) {
- ISelection selection = new StructuredSelection(nodes[0]);
- certificateChainViewer.setInput(new TreeNode[] { (TreeNode) nodes[0] });
- certificateChainViewer.setSelection(selection);
- listViewer.setSelection(selection);
- }
+ if (!artifactMap.isEmpty()) {
+ certifcateViewer.setSelection(new StructuredSelection(artifactMap.keySet().iterator().next()));
}
- return composite;
+
+ return mainComposite;
}
@Override
@@ -199,24 +191,20 @@ public class TrustCertificateDialog extends SelectionDialog {
createButton(parent, IDialogConstants.OK_ID, ProvUIMessages.TrustCertificateDialog_AcceptSelectedButtonLabel,
true);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
- super.getOkButton().setEnabled(false);
+ updateOkButton();
}
private void createButtons(Composite composite) {
Composite buttonComposite = new Composite(composite, SWT.NONE);
buttonComposite.setLayout(new RowLayout());
- // Details button to view certificate chain
+
detailsButton = new Button(buttonComposite, SWT.NONE);
detailsButton.setText(ProvUIMessages.TrustCertificateDialog_Details);
detailsButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
- Object o = selectedCertificate;
- if (selectedCertificate instanceof TreeNode) {
- o = ((TreeNode) selectedCertificate).getValue();
- }
- if (o instanceof X509Certificate) {
- X509Certificate cert = (X509Certificate) o;
+ X509Certificate cert = getInstance(certificateChainViewer.getSelection(), X509Certificate.class);
+ if (cert != null) {
X509CertificateViewDialog certificateDialog = new X509CertificateViewDialog(getShell(), cert);
certificateDialog.open();
}
@@ -228,46 +216,48 @@ public class TrustCertificateDialog extends SelectionDialog {
}
});
- Button exportButton = new Button(buttonComposite, SWT.NONE);
+ exportButton = new Button(buttonComposite, SWT.NONE);
exportButton.setText(ProvUIMessages.TrustCertificateDialog_Export);
exportButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
- Object o = selectedCertificate;
- if (selectedCertificate instanceof TreeNode) {
- o = ((TreeNode) selectedCertificate).getValue();
- }
- FileDialog destination = new FileDialog(detailsButton.getShell(), SWT.SAVE);
- destination.setText(ProvUIMessages.TrustCertificateDialog_Export);
- if (o instanceof X509Certificate) {
- X509Certificate cert = (X509Certificate) o;
- destination.setFilterExtensions(new String[] { "*.der" }); //$NON-NLS-1$
- destination.setFileName(cert.getSerialNumber().toString() + ".der"); //$NON-NLS-1$
- String path = destination.open();
- 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 if (o instanceof PGPPublicKey) {
- PGPPublicKey key = (PGPPublicKey) o;
- 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();
- if (path == null) {
- return;
- }
- File destinationFile = new File(path);
- try (OutputStream output = new ArmoredOutputStream(new FileOutputStream(destinationFile))) {
- output.write(key.getEncoded());
- } catch (IOException ex) {
- ProvUIActivator.getDefault().getLog()
- .log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, ex.getMessage(), ex));
+ 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));
+ }
}
}
}
@@ -276,7 +266,6 @@ public class TrustCertificateDialog extends SelectionDialog {
public void widgetSelected(SelectionEvent e) {
widgetDefaultSelected(e);
}
-
});
}
@@ -291,125 +280,264 @@ public class TrustCertificateDialog extends SelectionDialog {
return composite;
}
- @Override
- protected Label createMessageArea(Composite composite) {
- GridData data = new GridData(SWT.FILL, SWT.FILL, true, false);
+ 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);
- LabelFactory factory = WidgetFactory.label(SWT.WRAP).font(composite.getFont()).layoutData(data);
- if (getMessage() != null) {
- factory.text(getMessage());
- }
- return factory.create(composite);
+ 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 SashForm createUpperDialogArea(Composite parent) {
- Composite mainComposite = (Composite) super.createDialogArea(parent);
- initializeDialogUnits(mainComposite);
+ 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);
- SashForm sashForm = new SashForm(mainComposite, SWT.VERTICAL);
- sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- Composite composite = createSashFormArea(sashForm);
+ 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;
+ }
+ }
- createMessageArea(composite);
+ return super.getText(element);
+ }
+ });
- TableColumnLayout tableColumnLayout = new TableColumnLayout();
+ 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 | SWT.CHECK)
- .headerVisible(true).linesVisible(true).font(parent.getFont()).create(tableComposite);
- listViewer = new CheckboxTableViewer(table);
- listViewer.setContentProvider(contentProvider);
+ 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(10);
+ data.heightHint = convertHeightInCharsToPixels(Math.min(artifacts.size() + 1, 10)) * 3 / 2;
data.widthHint = convertWidthInCharsToPixels(120);
tableComposite.setLayoutData(data);
- TableViewerColumn typeColumn = new TableViewerColumn(listViewer, SWT.NONE);
- typeColumn.getColumn().setText(ProvUIMessages.TrustCertificateDialog_ObjectType);
- typeColumn.setLabelProvider(new PGPOrX509ColumnLabelProvider(key -> "PGP", cert -> "x509")); //$NON-NLS-1$ //$NON-NLS-2$
-
- TableViewerColumn idColumn = new TableViewerColumn(listViewer, SWT.NONE);
- idColumn.getColumn().setText(ProvUIMessages.TrustCertificateDialog_Id);
- idColumn.setLabelProvider(new PGPOrX509ColumnLabelProvider(TrustCertificateDialog::userFriendlyFingerPrint,
- cert -> cert.getSerialNumber().toString()));
-
- TableViewerColumn signerColumn = new TableViewerColumn(listViewer, SWT.NONE);
- signerColumn.getColumn().setText(ProvUIMessages.TrustCertificateDialog_Name);
- signerColumn.setLabelProvider(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();
- }));
-
- TableViewerColumn validColumn = new TableViewerColumn(listViewer, SWT.NONE);
- validColumn.getColumn().setText(ProvUIMessages.TrustCertificateDialog_dates);
- validColumn.setLabelProvider(new PGPOrX509ColumnLabelProvider(pgp -> {
- if (pgp.getCreationTime().after(Date.from(Instant.now()))) {
- return NLS.bind(ProvUIMessages.TrustCertificateDialog_NotYetValidStartDate, pgp.getCreationTime());
+ 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;
+ }
}
- long validSeconds = pgp.getValidSeconds();
- if (validSeconds == 0) {
- return ProvUIMessages.TrustCertificateDialog_valid;
+ 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);
}
- 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;
+ });
+
+ 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);
- // The first column is packed below.
- tableColumnLayout.setColumnData(typeColumn.getColumn(), new ColumnWeightData(1));
- tableColumnLayout.setColumnData(idColumn.getColumn(), new ColumnWeightData(10));
- tableColumnLayout.setColumnData(signerColumn.getColumn(), new ColumnWeightData(15));
- tableColumnLayout.setColumnData(validColumn.getColumn(), new ColumnWeightData(10));
+ artifactViewer.setInput(artifacts);
+
+ classifierColumn.getColumn().pack();
+ }
- Menu menu = new Menu(table);
- table.setMenu(menu);
+ 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 -> {
- Object o = ((IStructuredSelection) listViewer.getSelection()).getFirstElement();
- if (o instanceof TreeNode) {
- o = ((TreeNode) o).getValue();
- }
- if (o instanceof PGPPublicKey) {
- PGPPublicKey key = (PGPPublicKey) o;
+ 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();
}
}));
- listViewer.addSelectionChangedListener(e -> item.setEnabled(containsPGPKeys(e.getSelection())));
-
- addSelectionButtons(composite);
-
- listViewer.setInput(inputElement);
-
- typeColumn.getColumn().pack();
-
- if (!getInitialElementSelections().isEmpty()) {
- checkInitialSelections();
- }
-
- Dialog.applyDialogFont(composite);
+ viewer.addSelectionChangedListener(
+ e -> item.setEnabled(containsInstance(e.getSelection(), PGPPublicKey.class)));
+ }
- return sashForm;
+ 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;
}
/**
@@ -419,7 +547,10 @@ public class TrustCertificateDialog extends SelectionDialog {
private void checkInitialSelections() {
Iterator<?> itemsToCheck = getInitialElementSelections().iterator();
while (itemsToCheck.hasNext()) {
- listViewer.setChecked(itemsToCheck.next(), true);
+ certifcateViewer.setChecked(itemsToCheck.next(), true);
+ if (artifactViewer != null) {
+ artifactViewer.refresh(true);
+ }
}
}
@@ -441,8 +572,11 @@ public class TrustCertificateDialog extends SelectionDialog {
ProvUIMessages.TrustCertificateDialog_SelectAll, false);
SelectionListener listener = widgetSelectedAdapter(e -> {
- listViewer.setAllChecked(true);
- getOkButton().setEnabled(true);
+ certifcateViewer.setAllChecked(true);
+ if (artifactViewer != null) {
+ artifactViewer.refresh(true);
+ }
+ updateOkButton();
});
selectButton.addSelectionListener(listener);
@@ -450,79 +584,145 @@ public class TrustCertificateDialog extends SelectionDialog {
ProvUIMessages.TrustCertificateDialog_DeselectAll, false);
listener = widgetSelectedAdapter(e -> {
- listViewer.setAllChecked(false);
- getOkButton().setEnabled(false);
+ certifcateViewer.setAllChecked(false);
+ if (artifactViewer != null) {
+ artifactViewer.refresh(true);
+ }
+ updateOkButton();
});
deselectButton.addSelectionListener(listener);
}
- private ISelectionChangedListener getChainSelectionListener() {
- return event -> {
- ISelection selection = event.getSelection();
- if (selection instanceof StructuredSelection) {
- selectedCertificate = ((StructuredSelection) selection).getFirstElement();
- detailsButton.setEnabled(selectedCertificate instanceof TreeNode
- && ((TreeNode) selectedCertificate).getValue() instanceof X509Certificate);
- }
- };
+ 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;
}
- public TreeViewer getCertificateChainViewer() {
- return certificateChainViewer;
+ private void setFilterPath(String key, String filterPath) {
+ if (filterPath != null) {
+ IDialogSettings dialogSettings = DialogSettings
+ .getOrCreateSection(ProvUIActivator.getDefault().getDialogSettings(), getClass().getName());
+ dialogSettings.put(key, filterPath);
+ }
}
- private IDoubleClickListener getDoubleClickListener() {
- return event -> {
- StructuredSelection selection = (StructuredSelection) event.getSelection();
- Object selectedElement = selection.getFirstElement();
- if (selectedElement instanceof TreeNode) {
- TreeNode treeNode = (TreeNode) selectedElement;
- if (treeNode.getValue() instanceof X509Certificate) {
- // create and open dialog for certificate chain
- X509CertificateViewDialog certificateViewDialog = new X509CertificateViewDialog(getShell(),
- (X509Certificate) treeNode.getValue());
- certificateViewDialog.open();
+ 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());
}
- };
+ }
}
- private ISelectionChangedListener getParentSelectionListener() {
- return event -> {
- ISelection selection = event.getSelection();
- if (selection instanceof StructuredSelection) {
- TreeNode firstElement = (TreeNode) ((StructuredSelection) selection).getFirstElement();
- getCertificateChainViewer().setInput(new TreeNode[] { firstElement });
- getCertificateChainViewer().setSelection(new StructuredSelection(firstElement));
- Button okButton = getOkButton();
- if (okButton != null) {
- okButton.setEnabled(listViewer.getCheckedElements().length > 0);
- }
+ @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);
+ }
}
- /**
- * The <code>ListSelectionDialog</code> implementation of this
- * <code>Dialog</code> method builds a list of the selected elements for later
- * retrieval by the client and closes this dialog.
- */
- @Override
- protected void okPressed() {
- // Get the input children.
- Object[] children = contentProvider.getElements(inputElement);
+ 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;
+ }
- // Build a list of selected children.
+ @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) {
- ArrayList<Object> list = new ArrayList<>();
- for (Object element : children) {
- if (listViewer.getChecked(element)) {
- list.add(element);
+ 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;
}
}
- setResult(list);
}
- super.okPressed();
+ return null;
+ }
+
+ private static boolean containsInstance(Object element, Class<?> type) {
+ return getInstance(element, type) != null;
}
private static String userFriendlyFingerPrint(PGPPublicKey key) {
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
index af618c880..15f2ec920 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
@@ -280,20 +280,26 @@ TrustCertificateDialog_Details=\uD83D\uDD0D D&etails...
TrustCertificateDialog_Export=\uD83D\uDCE5 E&xport...
TrustCertificateDialog_Title=Trust
TrustCertificateDialog_Message=Do you trust these signers?
-TrustCertificateDialog_MessageWithPGP=Do you trust these signers? \
-\u26A0\uFE0F\u00A0The displayed originator names are not necessarily a reliable certification or origin. \
-For PGP keys, verification is typically achieved by querying the key\'s fingerprint against a trusted key server.
+TrustCertificateDialog_MessageUnsigned=\u26A0\uFE0F\u00A0Do you trust unsigned content of unknown origin?
+TrustCertificateDialog_MessageNameWarning=\u26A0\uFE0F\u00A0The displayed originator names are not necessarily a reliable certification of origin.
+TrustCertificateDialog_MessagePGP=For PG keys, verification is typically achieved by querying the key\'s fingerprint against a trusted key server.
TrustCertificateDialog_AcceptSelectedButtonLabel=&Trust Selected
+TrustCertificateDialog_ArtifactId=Id
TrustCertificateDialog_SelectAll=&Select All
TrustCertificateDialog_DeselectAll=&Deselect All
TrustCertificateDialog_ObjectType=Type
TrustCertificateDialog_Id=Id/Fingerprint
TrustCertificateDialog_Name=Name
+TrustCertificateDialog_Classifier=Classifier
TrustCertificateDialog_CopyFingerprint=Copy Fingerprint
TrustCertificateDialog_dates=Validity Dates
+TrustCertificateDialog_NotApplicable=n/a
TrustCertificateDialog_NotYetValidStartDate=\u274C Not yet valid, starts {0}
TrustCertificateDialog_expiredSince=\u274C Expired since {0}
TrustCertificateDialog_validExpires=\u2714\uFE0F Valid, expires {0}
TrustCertificateDialog_valid=\u2714\uFE0F Valid
TrustCertificateDialog_expired=\u274C Expired
-TrustCertificateDialog_notYetValid=\u274C Not yet valid \ No newline at end of file
+TrustCertificateDialog_notYetValid=\u274C Not yet valid
+TrustCertificateDialog_Unknown=Unknown
+TrustCertificateDialog_Unsigned=Unsigned
+TrustCertificateDialog_Version=Version

Back to the top