Even more refactoring

This commit is contained in:
Paul Schaub 2022-03-21 11:25:03 +01:00
parent f04a322ac4
commit c2d4d283bc
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
14 changed files with 140 additions and 49 deletions

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.cli;
import java.io.IOException;
/**
* {@link RuntimeException} wrapper for {@link IOException}.
* Background: We want to throw {@link IOException IOExceptions} in {@link Runnable#run()}.
*/
public class RuntimeIOException extends RuntimeException {
private final IOException ioException;
public RuntimeIOException(IOException ioe) {
super(ioe);
this.ioException = ioe;
}
public IOException getIoException() {
return ioException;
}
}

View file

@ -4,7 +4,8 @@
package pgp.wkd.cli;
import pgp.wkd.MissingUserIdException;
import pgp.wkd.exception.CertNotFetchableException;
import pgp.wkd.exception.RejectedCertificateException;
import pgp.wkd.cli.command.Fetch;
import picocli.CommandLine;
@ -28,8 +29,8 @@ public class WKDCLI {
.setExitCodeExceptionMapper(new CommandLine.IExitCodeExceptionMapper() {
@Override
public int getExitCode(Throwable exception) {
if (exception instanceof MissingUserIdException) {
return MissingUserIdException.ERROR_CODE;
if (exception instanceof RejectedCertificateException) {
return ((RejectedCertificateException) exception).getErrorCode();
} else if (exception instanceof CertNotFetchableException) {
return CertNotFetchableException.ERROR_CODE;
}

View file

@ -5,17 +5,15 @@
package pgp.wkd.cli.command;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.util.io.Streams;
import pgp.certificate_store.Certificate;
import pgp.wkd.discovery.CertificateDiscoverer;
import pgp.wkd.discovery.HttpsUrlConnectionCertificateFetcher;
import pgp.wkd.MalformedUserIdException;
import pgp.wkd.WKDAddress;
import pgp.wkd.WKDAddressHelper;
import pgp.wkd.discovery.DiscoveryResult;
import pgp.wkd.discovery.CertificateFetcher;
import pgp.wkd.cli.CertNotFetchableException;
import pgp.wkd.cli.HttpsCertificateDiscoverer;
import pgp.wkd.cli.RuntimeIOException;
import pgp.wkd.discovery.CertificateDiscoverer;
import pgp.wkd.discovery.CertificateFetcher;
import pgp.wkd.discovery.DiscoveryResult;
import pgp.wkd.discovery.HttpsUrlConnectionCertificateFetcher;
import pgp.wkd.exception.MalformedUserIdException;
import picocli.CommandLine;
import java.io.IOException;
@ -51,24 +49,14 @@ public class Fetch implements Runnable {
WKDAddress address = addressFromUserId(userId);
DiscoveryResult result = certificateDiscoverer.discover(address);
if (!result.isSuccessful()) {
throw new CertNotFetchableException("Cannot fetch cert.");
}
OutputStream outputStream = armor ? new ArmoredOutputStream(System.out) : System.out;
try {
if (armor) {
OutputStream out = new ArmoredOutputStream(System.out);
for (Certificate certificate : result.getCertificates()) {
Streams.pipeAll(certificate.getInputStream(), out);
}
out.close();
} else {
for (Certificate certificate : result.getCertificates()) {
Streams.pipeAll(certificate.getInputStream(), System.out);
}
result.write(outputStream);
if (outputStream instanceof ArmoredOutputStream) {
outputStream.close();
}
} catch (IOException e) {
throw new CertNotFetchableException("Certificate cannot be fetched.", e);
throw new RuntimeIOException(e);
}
}

View file

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd;
/**
* Exception that gets thrown when an OpenPGP certificate is not carrying a User-ID binding for the email address
* that was used to look the certificate up via WKD.
*/
public class MissingUserIdException extends RuntimeException {
public static final int ERROR_CODE = 7;
public MissingUserIdException(String message) {
super(message);
}
}

View file

@ -6,6 +6,7 @@ package pgp.wkd;
import org.apache.commons.codec.binary.ZBase32;
import pgp.wkd.discovery.DiscoveryMethod;
import pgp.wkd.exception.MalformedUserIdException;
import javax.annotation.Nonnull;
import java.io.UnsupportedEncodingException;

View file

@ -4,6 +4,8 @@
package pgp.wkd;
import pgp.wkd.exception.MalformedUserIdException;
import javax.annotation.Nonnull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

View file

@ -4,7 +4,7 @@
package pgp.wkd.discovery;
import pgp.wkd.MalformedUserIdException;
import pgp.wkd.exception.MalformedUserIdException;
import pgp.wkd.WKDAddress;
import pgp.wkd.WKDAddressHelper;

View file

@ -6,7 +6,7 @@ package pgp.wkd.discovery;
import pgp.certificate_store.Certificate;
import pgp.wkd.CertificateAndUserIds;
import pgp.wkd.MissingUserIdException;
import pgp.wkd.exception.RejectedCertificateException;
import pgp.wkd.RejectedCertificate;
import pgp.wkd.WKDAddress;
@ -47,7 +47,7 @@ public class DefaultCertificateDiscoverer implements CertificateDiscoverer {
}
if (!containsEmail) {
rejectedCertificates.add(new RejectedCertificate(certificate,
new MissingUserIdException("Certificate " + certificate.getFingerprint() +
new RejectedCertificateException.MissingUserId("Certificate " + certificate.getFingerprint() +
" does not contain user-id with email '" + email + "'")));
} else {
acceptableCertificates.add(certificate);

View file

@ -5,8 +5,12 @@
package pgp.wkd.discovery;
import pgp.certificate_store.Certificate;
import pgp.wkd.exception.CertNotFetchableException;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@ -39,6 +43,27 @@ public class DiscoveryResult {
return false;
}
/**
* Write out the (successful) result (certificates) to the given {@link OutputStream}.
* This method does not close the output stream.
*
* @param outputStream output stream
*/
public void write(OutputStream outputStream) throws IOException {
if (!isSuccessful()) {
throw new CertNotFetchableException("Cannot fetch cert.");
}
byte[] buf = new byte[4096];
int read;
for (Certificate certificate : getCertificates()) {
InputStream certIn = certificate.getInputStream();
while ((read = certIn.read(buf)) != -1) {
outputStream.write(buf, 0, read);
}
}
}
@Nonnull
public List<DiscoveryResponse> getItems() {
return items;

View file

@ -2,8 +2,11 @@
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.cli;
package pgp.wkd.exception;
/**
* Exception that gets thrown when a certificate cannot be fetched at all.
*/
public class CertNotFetchableException extends RuntimeException {
public static final int ERROR_CODE = 3;

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd;
package pgp.wkd.exception;
/**
* Exception that gets thrown when the application is presented with a malformed user-id.

View file

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.exception;
/**
* Subclasses of this exception are thrown when a fetched certificate is rejected for any reason.
*/
public abstract class RejectedCertificateException extends RuntimeException {
public RejectedCertificateException(String message) {
super(message);
}
/**
* Return an error code that identifies the exception.
* @return error code
*/
public abstract int getErrorCode();
/**
* Exception that gets thrown when an OpenPGP certificate is not carrying a User-ID binding for the email address
* that was used to look the certificate up via WKD.
*/
public static class MissingUserId extends RejectedCertificateException {
public static final int ERROR_CODE = 7;
public MissingUserId(String message) {
super(message);
}
@Override
public int getErrorCode() {
return ERROR_CODE;
}
}
}

View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Exceptions.
*/
package pgp.wkd.exception;

View file

@ -11,6 +11,7 @@ import java.net.URI;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import pgp.wkd.exception.MalformedUserIdException;
public class WKDAddressTest {
@ -70,6 +71,22 @@ public class WKDAddressTest {
}
}
@Test
public void fromLocalAndDomainPartTest() {
String validLocalPart = "Alice93";
String validDomainPart = "pgpainless.org";
String invalidLocalPart = "contains whitespace";
String invalidDomainPart = "contains white.space";
WKDAddress address = WKDAddress.fromLocalAndDomainPart(validLocalPart, validDomainPart);
assertEquals("Alice93@pgpainless.org", address.getEmail());
assertThrows(IllegalArgumentException.class, () -> WKDAddress.fromLocalAndDomainPart(invalidLocalPart, validDomainPart));
assertThrows(IllegalArgumentException.class, () -> WKDAddress.fromLocalAndDomainPart(validLocalPart, invalidDomainPart));
assertThrows(IllegalArgumentException.class, () -> WKDAddress.fromLocalAndDomainPart(invalidLocalPart, invalidDomainPart));
}
@Test
public void testFromInvalidEmail() {
for (String brokenEmail : Arrays.asList("john.doe", "@example.org", "john doe@example.org", "john.doe@example org")) {