mirror of
https://codeberg.org/PGPainless/wkd-java.git
synced 2024-11-21 23:02:05 +01:00
Javadoc
This commit is contained in:
parent
d0a161e87a
commit
df85b4202d
9 changed files with 224 additions and 41 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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 <pre>address</pre> via the given <pre>method</pre>.
|
||||
*
|
||||
* @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<DiscoveryResponse> 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));
|
||||
}
|
||||
|
|
|
@ -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<CertificateAndUserIds> read(InputStream inputStream) throws IOException;
|
||||
}
|
||||
|
|
|
@ -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<Certificate> 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<RejectedCertificate> 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<Certificate> acceptableCertificates) {
|
||||
Builder setAcceptableCertificates(List<Certificate> acceptableCertificates) {
|
||||
this.acceptableCertificates = acceptableCertificates;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRejectedCertificates(List<RejectedCertificate> rejectedCertificates) {
|
||||
Builder setRejectedCertificates(List<RejectedCertificate> 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,
|
||||
|
|
|
@ -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<DiscoveryResponse> items;
|
||||
private final List<DiscoveryResponse> 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<DiscoveryResponse> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of acceptable certificates that were discovered.
|
||||
*
|
||||
* @return certificates
|
||||
*/
|
||||
@Nonnull
|
||||
public List<Certificate> getCertificates() {
|
||||
List<Certificate> 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<DiscoveryResponse> getItems() {
|
||||
public List<DiscoveryResponse> getResponses() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<DiscoveryResponse> getFailedItems() {
|
||||
List<DiscoveryResponse> fails = new ArrayList<>();
|
||||
for (DiscoveryResponse item : items) {
|
||||
if (!item.isSuccessful()) {
|
||||
fails.add(item);
|
||||
}
|
||||
}
|
||||
return fails;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 <pre>true</pre> if the <pre>mailbox-only</pre> 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 <pre>true</pre> if the <pre>dane-only</pre> 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 <pre>true</pre> if the <pre>auth-submit</pre> 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 <pre>submission-address</pre>.
|
||||
*
|
||||
* 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;
|
||||
|
|
Loading…
Reference in a new issue