diff --git a/wkd-java-cli/src/main/java/pgp/wkd/cli/command/Fetch.java b/wkd-java-cli/src/main/java/pgp/wkd/cli/command/Fetch.java
index 91d008e..b977bf2 100644
--- a/wkd-java-cli/src/main/java/pgp/wkd/cli/command/Fetch.java
+++ b/wkd-java-cli/src/main/java/pgp/wkd/cli/command/Fetch.java
@@ -10,7 +10,7 @@ import pgp.wkd.WKDAddressHelper;
import pgp.wkd.cli.PGPainlessCertificateParser;
import pgp.wkd.cli.RuntimeIOException;
import pgp.wkd.discovery.CertificateDiscoverer;
-import pgp.wkd.discovery.DefaultCertificateDiscoverer;
+import pgp.wkd.discovery.ValidatingCertificateDiscoverer;
import pgp.wkd.discovery.DiscoveryResult;
import pgp.wkd.discovery.HttpsUrlConnectionCertificateFetcher;
import pgp.wkd.exception.MalformedUserIdException;
@@ -39,7 +39,7 @@ public class Fetch implements Runnable {
)
boolean armor = false;
- public static final CertificateDiscoverer DEFAULT_DISCOVERER = new DefaultCertificateDiscoverer(
+ public static final CertificateDiscoverer DEFAULT_DISCOVERER = new ValidatingCertificateDiscoverer(
new PGPainlessCertificateParser(), new HttpsUrlConnectionCertificateFetcher());
private static CertificateDiscoverer discoverer = DEFAULT_DISCOVERER;
diff --git a/wkd-java-cli/src/test/java/pgp/wkd/cli/test_suite/TestSuiteTestRunner.java b/wkd-java-cli/src/test/java/pgp/wkd/cli/test_suite/TestSuiteTestRunner.java
index e3ee2a2..a7596d3 100644
--- a/wkd-java-cli/src/test/java/pgp/wkd/cli/test_suite/TestSuiteTestRunner.java
+++ b/wkd-java-cli/src/test/java/pgp/wkd/cli/test_suite/TestSuiteTestRunner.java
@@ -12,7 +12,7 @@ import pgp.wkd.cli.PGPainlessCertificateParser;
import pgp.wkd.cli.WKDCLI;
import pgp.wkd.cli.command.Fetch;
import pgp.wkd.discovery.CertificateDiscoverer;
-import pgp.wkd.discovery.DefaultCertificateDiscoverer;
+import pgp.wkd.discovery.ValidatingCertificateDiscoverer;
import pgp.wkd.discovery.DiscoveryMethod;
import pgp.wkd.test_suite.TestCase;
import pgp.wkd.test_suite.TestSuite;
@@ -43,7 +43,7 @@ public class TestSuiteTestRunner {
suite = generator.generateTestSuiteInDirectory(tempFile, DiscoveryMethod.direct);
// Fetch certificates from a local directory instead of the internetzzz.
- CertificateDiscoverer discoverer = new DefaultCertificateDiscoverer(
+ CertificateDiscoverer discoverer = new ValidatingCertificateDiscoverer(
new PGPainlessCertificateParser(), new DirectoryBasedCertificateFetcher(tempPath));
Fetch.setCertificateDiscoverer(discoverer);
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/AbstractUriCertificateFetcher.java b/wkd-java/src/main/java/pgp/wkd/discovery/AbstractUriCertificateFetcher.java
index 7383d89..56490af 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/AbstractUriCertificateFetcher.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/AbstractUriCertificateFetcher.java
@@ -12,10 +12,27 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+/**
+ * Abstract implementation of the {@link CertificateFetcher} interface.
+ * The purpose of this class is to map {@link #fetchCertificate(WKDAddress, DiscoveryMethod)}
+ * and {@link #fetchPolicy(WKDAddress, DiscoveryMethod)} calls to {@link #fetchFromUri(URI)}.
+ *
+ * A concrete implementation of this class then simply needs to implement the latter method.
+ */
public abstract class AbstractUriCertificateFetcher implements CertificateFetcher {
private static final Logger LOGGER = LoggerFactory.getLogger(CertificateFetcher.class);
+ /**
+ * Fetch the contents of the file that the {@link URI} points to from the remote server.
+ * @param uri uri
+ * @return file contents
+ *
+ * @throws java.net.ConnectException in case the file or host does not exist
+ * @throws IOException in case of an IO-error
+ */
+ protected abstract InputStream fetchFromUri(URI uri) throws IOException;
+
@Override
public InputStream fetchCertificate(WKDAddress address, DiscoveryMethod method) throws IOException {
URI uri = address.getUri(method);
@@ -38,14 +55,4 @@ public abstract class AbstractUriCertificateFetcher implements CertificateFetche
}
}
- /**
- * Fetch the contents of the file that the {@link URI} points to from the remote server.
- * @param uri uri
- * @return file contents
- *
- * @throws java.net.ConnectException in case the file or host does not exist
- * @throws IOException in case of an IO-error
- */
- protected abstract InputStream fetchFromUri(URI uri) throws IOException;
-
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/CertificateDiscoverer.java b/wkd-java/src/main/java/pgp/wkd/discovery/CertificateDiscoverer.java
index 6b11e77..473c0be 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/CertificateDiscoverer.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/CertificateDiscoverer.java
@@ -11,10 +11,26 @@ import pgp.wkd.WKDAddressHelper;
import java.util.ArrayList;
import java.util.List;
+/**
+ * Interface which describes an API to discover OpenPGP certificates via the WKD.
+ */
public interface CertificateDiscoverer {
+ /**
+ * Discover OpenPGP certificates by querying the given
address
via the given method
.
+ *
+ * @param method discovery method
+ * @param address wkd address
+ * @return response
+ */
DiscoveryResponse discover(DiscoveryMethod method, WKDAddress address);
+ /**
+ * Discover OpenPGP certificates by {@link WKDAddress}.
+ *
+ * @param address address
+ * @return discovery result
+ */
default DiscoveryResult discover(WKDAddress address) {
List results = new ArrayList<>();
@@ -31,10 +47,26 @@ public interface CertificateDiscoverer {
return new DiscoveryResult(results);
}
+ /**
+ * Discover OpenPGP certificates by email address.
+ *
+ * @param email email address
+ * @return discovery result
+ *
+ * @throws MalformedUserIdException in case of a malformed email address
+ */
default DiscoveryResult discoverByEmail(String email) throws MalformedUserIdException {
return discover(WKDAddress.fromEmail(email));
}
+ /**
+ * Discover OpenPGP certificates by user-id.
+ *
+ * @param userId user-id
+ * @return discovery result
+ *
+ * @throws MalformedUserIdException in case of a malformed user-id
+ */
default DiscoveryResult discoverByUserId(String userId) throws MalformedUserIdException {
return discover(WKDAddressHelper.wkdAddressFromUserId(userId));
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/CertificateParser.java b/wkd-java/src/main/java/pgp/wkd/discovery/CertificateParser.java
index 001db2b..5e678b0 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/CertificateParser.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/CertificateParser.java
@@ -10,7 +10,22 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
+/**
+ * Interface for an OpenPGP certificate parser class.
+ */
public interface CertificateParser {
+ /**
+ * Read a list of OpenPGP certificates from the given input stream.
+ * The input stream contains binary OpenPGP certificate data.
+ *
+ * The result is a list of {@link CertificateAndUserIds}, where {@link CertificateAndUserIds#getUserIds()} only
+ * contains validly bound user-ids.
+ *
+ * @param inputStream input stream of binary OpenPGP certificates
+ * @return list of parsed certificates and their user-ids
+ *
+ * @throws IOException in case of an IO error
+ */
List read(InputStream inputStream) throws IOException;
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResponse.java b/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResponse.java
index 1dd0fb6..e1b6ac1 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResponse.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResponse.java
@@ -14,6 +14,9 @@ import javax.annotation.Nullable;
import java.net.URI;
import java.util.List;
+/**
+ * A single response to a WKD query.
+ */
public final class DiscoveryResponse {
private final DiscoveryMethod method;
@@ -49,47 +52,100 @@ public final class DiscoveryResponse {
this.missingPolicyFileException = missingPolicyFileException;
}
+ /**
+ * Return the method that was used to fetch this response.
+ *
+ * @return method
+ */
@Nonnull
public DiscoveryMethod getMethod() {
return method;
}
+ /**
+ * Return the WKD-Address which is queried.
+ *
+ * @return address
+ */
@Nonnull
public WKDAddress getAddress() {
return address;
}
+ /**
+ * Return the URI that was queried against.
+ *
+ * @return URI
+ */
public URI getUri() {
return getAddress().getUri(getMethod());
}
+ /**
+ * Return true, if the query was successful.
+ * That is, if there were no fetching errors, and if the server presented a policy.
+ *
+ * @return success
+ */
public boolean isSuccessful() {
return !hasFetchingFailure() && hasPolicy();
}
+ /**
+ * Return the list of acceptable certificates that were returned by the WKD service.
+ *
+ * @return certificates
+ */
@Nonnull
public List getCertificates() {
return certificates;
}
+ /**
+ * Return a list containing all rejected certificates returned by the WKD service.
+ * Certificates can be rejected for several reasons such as a missing user-id, or if the certificate is malformed.
+ *
+ * @return list of rejected certificates
+ */
@Nonnull
public List getRejectedCertificates() {
return rejectedCertificates;
}
+ /**
+ * Return the cause of fetching errors, if any.
+ * A fetching failure might be e.g. a connection exception in case the WKD service cannot be reached.
+ *
+ * @return fetching failure
+ */
@Nullable
public Throwable getFetchingFailure() {
return fetchingFailure;
}
+ /**
+ * Return true, if the result contains acceptable certificates.
+ *
+ * @return true if the response has certificates
+ */
public boolean hasCertificates() {
return certificates != null && !certificates.isEmpty();
}
+ /**
+ * Return true, if there was a fetching failure.
+ *
+ * @return true if failure
+ */
public boolean hasFetchingFailure() {
return fetchingFailure != null;
}
+ /**
+ * Return true, if the WKD service presented a policy.
+ *
+ * @return true if policy available
+ */
public boolean hasPolicy() {
return getPolicy() != null;
}
@@ -99,12 +155,18 @@ public final class DiscoveryResponse {
return policy;
}
- public static Builder builder(@Nonnull DiscoveryMethod discoveryMethod, @Nonnull WKDAddress address) {
- Builder builder = new Builder(discoveryMethod, address);
- return builder;
+ /**
+ * Builder for {@link DiscoveryResponse}.
+ *
+ * @param discoveryMethod method used for discovery
+ * @param address WKD address
+ * @return builder
+ */
+ static Builder builder(@Nonnull DiscoveryMethod discoveryMethod, @Nonnull WKDAddress address) {
+ return new Builder(discoveryMethod, address);
}
- public static class Builder {
+ static class Builder {
private DiscoveryMethod discoveryMethod;
private WKDAddress address;
@@ -114,37 +176,37 @@ public final class DiscoveryResponse {
private WKDPolicy policy;
private MissingPolicyFileException missingPolicyFileException;
- public Builder(DiscoveryMethod discoveryMethod, WKDAddress address) {
+ Builder(DiscoveryMethod discoveryMethod, WKDAddress address) {
this.discoveryMethod = discoveryMethod;
this.address = address;
}
- public Builder setAcceptableCertificates(List acceptableCertificates) {
+ Builder setAcceptableCertificates(List acceptableCertificates) {
this.acceptableCertificates = acceptableCertificates;
return this;
}
- public Builder setRejectedCertificates(List rejectedCertificates) {
+ Builder setRejectedCertificates(List rejectedCertificates) {
this.rejectedCertificates = rejectedCertificates;
return this;
}
- public Builder setFetchingFailure(Throwable throwable) {
+ Builder setFetchingFailure(Throwable throwable) {
this.fetchingFailure = throwable;
return this;
}
- public Builder setPolicy(WKDPolicy policy) {
+ Builder setPolicy(WKDPolicy policy) {
this.policy = policy;
return this;
}
- public Builder setMissingPolicyFileException(MissingPolicyFileException exception) {
+ Builder setMissingPolicyFileException(MissingPolicyFileException exception) {
this.missingPolicyFileException = exception;
return this;
}
- public DiscoveryResponse build() {
+ DiscoveryResponse build() {
return new DiscoveryResponse(
discoveryMethod,
address,
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResult.java b/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResult.java
index 4633fc6..0030812 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResult.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/DiscoveryResult.java
@@ -14,14 +14,28 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
+/**
+ * Result of discovering an OpenPGP certificate via WKD.
+ */
public class DiscoveryResult {
- private List items;
+ private final List items;
+ /**
+ * Create a {@link DiscoveryResult} from a list of {@link DiscoveryResponse DiscoveryResponses}.
+ * Usually the list contains one or two responses (one for each {@link DiscoveryMethod}.
+ *
+ * @param items responses
+ */
public DiscoveryResult(@Nonnull List items) {
this.items = items;
}
+ /**
+ * Return the list of acceptable certificates that were discovered.
+ *
+ * @return certificates
+ */
@Nonnull
public List getCertificates() {
List certificates = new ArrayList<>();
@@ -34,6 +48,11 @@ public class DiscoveryResult {
return certificates;
}
+ /**
+ * Return true, if at least one {@link DiscoveryResponse} was successful and contained acceptable certificates.
+ *
+ * @return success
+ */
public boolean isSuccessful() {
for (DiscoveryResponse item : items) {
if (item.isSuccessful() && item.hasCertificates()) {
@@ -69,7 +88,7 @@ public class DiscoveryResult {
private void throwCertNotFetchableException() {
Throwable cause = null;
- for (DiscoveryResponse response : getItems()) {
+ for (DiscoveryResponse response : getResponses()) {
// Find the most "useful" exception.
// Rejections are more useful than fetching failures
if (!response.getRejectedCertificates().isEmpty()) {
@@ -82,19 +101,13 @@ public class DiscoveryResult {
throw new CertNotFetchableException("Could not fetch certificates.", cause);
}
+ /**
+ * Return the list of responses.
+ *
+ * @return responses
+ */
@Nonnull
- public List getItems() {
+ public List getResponses() {
return items;
}
-
- @Nonnull
- public List getFailedItems() {
- List fails = new ArrayList<>();
- for (DiscoveryResponse item : items) {
- if (!item.isSuccessful()) {
- fails.add(item);
- }
- }
- return fails;
- }
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/DefaultCertificateDiscoverer.java b/wkd-java/src/main/java/pgp/wkd/discovery/ValidatingCertificateDiscoverer.java
similarity index 90%
rename from wkd-java/src/main/java/pgp/wkd/discovery/DefaultCertificateDiscoverer.java
rename to wkd-java/src/main/java/pgp/wkd/discovery/ValidatingCertificateDiscoverer.java
index ae5ff9b..2613ce8 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/DefaultCertificateDiscoverer.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/ValidatingCertificateDiscoverer.java
@@ -16,12 +16,16 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
-public class DefaultCertificateDiscoverer implements CertificateDiscoverer {
+/**
+ * Default implementation of the {@link CertificateDiscoverer}.
+ * This implementation validates the received certificates.
+ */
+public class ValidatingCertificateDiscoverer implements CertificateDiscoverer {
protected final CertificateParser reader;
protected final CertificateFetcher fetcher;
- public DefaultCertificateDiscoverer(CertificateParser reader, CertificateFetcher fetcher) {
+ public ValidatingCertificateDiscoverer(CertificateParser reader, CertificateFetcher fetcher) {
this.reader = reader;
this.fetcher = fetcher;
}
diff --git a/wkd-java/src/main/java/pgp/wkd/discovery/WKDPolicy.java b/wkd-java/src/main/java/pgp/wkd/discovery/WKDPolicy.java
index 5007d5d..5d4cfc1 100644
--- a/wkd-java/src/main/java/pgp/wkd/discovery/WKDPolicy.java
+++ b/wkd-java/src/main/java/pgp/wkd/discovery/WKDPolicy.java
@@ -10,6 +10,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+/**
+ * Class describing the contents of a policy file.
+ * The WKD policy file is found at ".well-known/policy"
+ */
public final class WKDPolicy {
public static final String KEYWORD_MAILBOX_ONLY = "mailbox-only";
@@ -83,23 +87,69 @@ public final class WKDPolicy {
return new WKDPolicy(mailboxOnly, daneOnly, authSubmit, protocolVersion, submissionAddress);
}
+ /**
+ * Return true
if the mailbox-only
flag is set.
+ *
+ * The mail server provider does only accept keys with only a mailbox in the User ID.
+ * In particular User IDs with a real name in addition to the mailbox will be rejected as invalid.
+ *
+ * @return whether mailbox-only flag is set
+ */
public boolean isMailboxOnly() {
return mailboxOnly;
}
+ /**
+ * Return true
if the dane-only
flag is set.
+ *
+ * The mail server provider does not run a Web Key Directory but only an OpenPGP DANE service.
+ * The Web Key Directory Update protocol is used to update the keys for the DANE service.
+ *
+ * @return whether dane-only flag is set
+ */
public boolean isDaneOnly() {
return daneOnly;
}
+ /**
+ * Return true
if the auth-submit
flag is set.
+ *
+ * The submission of the mail to the server is done using an authenticated connection.
+ * Thus the submitted key will be published immediately without any confirmation request.
+ *
+ * @return whether auth-submit flag is set
+ */
public boolean isAuthSubmit() {
return authSubmit;
}
+ /**
+ * Return the protocol version.
+ *
+ * This keyword can be used to explicitly claim the support of a specific version of the Web Key Directory
+ * update protocol.
+ * This is in general not needed but implementations may have workarounds for providers which only support
+ * an old protocol version.
+ * If these providers update to a newer version they should add this keyword so that the implementation
+ * can disable the workaround.
+ * The value is an integer corresponding to the respective draft revision number.
+ *
+ * @return value of the protocol-version field
+ */
@Nullable
public Integer getProtocolVersion() {
return protocolVersion;
}
+ /**
+ * Return the submission-address
.
+ *
+ * An alternative way to specify the submission address.
+ * The value is the addr-spec part of the address to send requests to this server.
+ * If this keyword is used in addition to the submission-address file, both MUST have the same value.
+ *
+ * @return value of the submission-address field
+ */
@Nullable
public String getSubmissionAddress() {
return submissionAddress;