diff --git a/acme4j-client/src/main/java/module-info.java b/acme4j-client/src/main/java/module-info.java index 1d3df187..e9d9eb04 100644 --- a/acme4j-client/src/main/java/module-info.java +++ b/acme4j-client/src/main/java/module-info.java @@ -12,6 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This is the main module of the acme4j client. + */ module org.shredzone.acme4j { requires static com.github.spotbugs.annotations; requires java.net.http; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java index 2c9415bd..edfc0507 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Account.java @@ -37,7 +37,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Represents an account at the ACME server. + * A representation of an account at the ACME server. */ public class Account extends AcmeJsonResource { private static final long serialVersionUID = 7042863483428051319L; @@ -65,7 +65,9 @@ public class Account extends AcmeJsonResource { } /** - * List of contact addresses (emails, phone numbers etc). + * List of registered contact addresses (emails, phone numbers etc). + *

+ * This list is unmodifiable. Use {@link #modify()} to change the contacts. */ public List getContacts() { return getJSON().get(KEY_CONTACT) @@ -110,20 +112,20 @@ public class Account extends AcmeJsonResource { } /** - * Returns an {@link Iterator} of all {@link Order} belonging to this {@link Account}. + * Returns an {@link Iterator} of all {@link Order} belonging to this + * {@link Account}. *

* Using the iterator will initiate one or more requests to the ACME server. * * @return {@link Iterator} instance that returns {@link Order} objects in no specific - * order. {@link Iterator#hasNext()} and {@link Iterator#next()} may throw - * {@link AcmeProtocolException} if a batch of authorization URIs could not be - * fetched from the server. Each {@link Iterator} instance may provide the - * {@link Order} objects in a different order. + * sorting order. {@link Iterator#hasNext()} and {@link Iterator#next()} may throw + * {@link AcmeProtocolException} if a batch of authorization URIs could not be fetched + * from the server. */ public Iterator getOrders() { var ordersUrl = getJSON().get(KEY_ORDERS).optional().map(Value::asURL); if (ordersUrl.isEmpty()) { - // Let's Encrypt does not provide this field at the moment although it's required. + // Let's Encrypt does not provide this field at the moment, although it's required. // See https://github.com/letsencrypt/boulder/issues/3335 throw new AcmeProtocolException("This ACME server does not support getOrders()"); } @@ -209,11 +211,11 @@ public class Account extends AcmeJsonResource { /** * Changes the {@link KeyPair} associated with the account. *

- * After a successful call, the new key pair is used in the bound {@link Session}, - * and the old key pair can be disposed of. + * After a successful call, the new key pair is already set in the associated + * {@link Login}. The old key pair can be discarded. * * @param newKeyPair - * new {@link KeyPair} to be used for identifying this account + * new {@link KeyPair} to be used for identifying this account */ public void changeKey(KeyPair newKeyPair) throws AcmeException { Objects.requireNonNull(newKeyPair, "newKeyPair"); @@ -267,7 +269,7 @@ public class Account extends AcmeJsonResource { } /** - * Editable {@link Account}. + * Provides editable properties of an {@link Account}. */ public class EditableAccount { private final List editContacts = new ArrayList<>(); @@ -279,6 +281,10 @@ public class Account extends AcmeJsonResource { /** * Returns the list of all contact URIs for modification. Use the {@link List} * methods to modify the contact list. + *

+ * The modified list is not validated. If you change entries, you have to make + * sure that they are valid according to the RFC. It is recommended to use + * the {@code addContact()} methods below to add new contacts to the list. */ public List getContacts() { return editContacts; @@ -314,8 +320,8 @@ public class Account extends AcmeJsonResource { /** * Adds a new Contact email to the account. *

- * This is a convenience call for {@link #addContact(String)} hat doesn't - * require from you attach "mailto" scheme before email address. + * This is a convenience call for {@link #addContact(String)} that doesn't + * require to prepend the email address with the "mailto" scheme. * * @param email * Contact email without "mailto" scheme (e.g. test@gmail.com) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java index 72faaf83..e9e30d2e 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/AccountBuilder.java @@ -34,7 +34,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * A builder for registering a new account. + * A builder for registering a new account with the CA. + *

+ * You need to create a new key pair and set it via {@link #useKeyPair(KeyPair)}. Your + * account will be identified by the public part of that key pair, so make sure to store + * it safely! There is no automatic way to regain access to your account if the key pair + * is lost. + *

+ * Depending on the CA you register with, you might need to give additional information. + *

*/ public class AccountBuilder { private static final Logger LOG = LoggerFactory.getLogger(AccountBuilder.class); @@ -48,9 +62,12 @@ public class AccountBuilder { /** * Add a contact URI to the list of contacts. + *

+ * A contact URI may be e.g. an email address or a phone number. It depends on the CA + * what kind of contact URIs are accepted, and how many must be provided as minimum. * * @param contact - * Contact URI + * Contact URI * @return itself */ public AccountBuilder addContact(URI contact) { @@ -65,10 +82,10 @@ public class AccountBuilder { * This is a convenience call for {@link #addContact(URI)}. * * @param contact - * Contact URI as string - * @throws IllegalArgumentException - * if there is a syntax error in the URI string + * Contact URI as string * @return itself + * @throws IllegalArgumentException + * if there is a syntax error in the URI string */ public AccountBuilder addContact(String contact) { addContact(URI.create(contact)); @@ -76,16 +93,16 @@ public class AccountBuilder { } /** - * Add a email address to the list of contacts. + * Add an email address to the list of contacts. *

- * This is a convenience call for {@link #addContact(String)} that doesn't - * require from you attach "mailto" scheme before email address. + * This is a convenience call for {@link #addContact(String)} that doesn't require + * to prepend the "mailto" scheme to an email address. * * @param email - * Contact email without "mailto" scheme (e.g. test@gmail.com) - * @throws IllegalArgumentException - * if there is a syntax error in the URI string + * Contact email without "mailto" scheme (e.g. test@gmail.com) * @return itself + * @throws IllegalArgumentException + * if there is a syntax error in the URI string */ public AccountBuilder addEmail(String email) { addContact("mailto:" + email); @@ -93,7 +110,12 @@ public class AccountBuilder { } /** - * Signals that the user agrees to the terms of service. + * Documents that the user has agreed to the terms of service. + *

+ * If the CA requires the user to agree to the terms of service, it is your + * responsibility to present them to the user, and actively ask for their agreement. A + * link to the terms of service is provided via + * {@code session.getMetadata().getTermsOfService()}. * * @return itself */ @@ -104,8 +126,13 @@ public class AccountBuilder { /** * Signals that only an existing account should be returned. The server will not - * create a new account if the key is not known. This is useful if you only have your - * account's key pair available, but not your account's location URL. + * create a new account if the key is not known. + *

+ * If you have lost your account's location URL, but still have your account's key + * pair, you can register your account again with the same key, and use + * {@link #onlyExisting()} to make sure that your existing account is returned. If + * your key is unknown to the server, an error is thrown once the account is to be + * created. * * @return itself */ @@ -116,9 +143,15 @@ public class AccountBuilder { /** * Sets the {@link KeyPair} to be used for this account. + *

+ * Only the public key of the pair is sent to the server for registration. acme4j will + * never send the private key part. + *

+ * Make sure to store your key pair safely after registration! There is no automatic + * way to regain access to your account if the key pair is lost. * * @param keyPair - * Account's {@link KeyPair} + * Account's {@link KeyPair} * @return itself */ public AccountBuilder useKeyPair(KeyPair keyPair) { @@ -128,13 +161,16 @@ public class AccountBuilder { /** * Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires - * an individual account identification, e.g. your customer number. + * an individual account identification (e.g. your customer number) and a shared + * secret for registration. See the documentation of your CA about how to retrieve the + * key identifier and MAC key. * * @param kid - * Key Identifier + * Key Identifier * @param macKey - * MAC key + * MAC key * @return itself + * @see #withKeyIdentifier(String, String) */ public AccountBuilder withKeyIdentifier(String kid, SecretKey macKey) { if (kid != null && kid.isEmpty()) { @@ -147,13 +183,20 @@ public class AccountBuilder { /** * Sets a Key Identifier and MAC key provided by the CA. Use this if your CA requires - * an individual account identification, e.g. your customer number. + * an individual account identification (e.g. your customer number) and a shared + * secret for registration. See the documentation of your CA about how to retrieve the + * key identifier and MAC key. + *

+ * This is a convenience call of {@link #withKeyIdentifier(String, SecretKey)} that + * accepts a base64url encoded MAC key, so both parameters can be passed in as + * strings. * * @param kid - * Key Identifier + * Key Identifier * @param encodedMacKey - * Base64url encoded MAC key. It will be decoded for your convenience. + * Base64url encoded MAC key. * @return itself + * @see #withKeyIdentifier(String, SecretKey) */ public AccountBuilder withKeyIdentifier(String kid, String encodedMacKey) { var encodedKey = AcmeUtils.base64UrlDecode(requireNonNull(encodedMacKey, "encodedMacKey")); @@ -162,10 +205,14 @@ public class AccountBuilder { /** * Creates a new account. + *

+ * Use this method to finally create your account with the given parameters. Do not + * use the {@link AccountBuilder} after invoking this method. * * @param session - * {@link Session} to be used for registration + * {@link Session} to be used for registration * @return {@link Account} referring to the new account + * @see #createLogin(Session) */ public Account create(Session session) throws AcmeException { return createLogin(session).getAccount(); @@ -174,10 +221,11 @@ public class AccountBuilder { /** * Creates a new account. *

- * This method returns a ready to use {@link Login} for the new {@link Account}. + * This method is identical to {@link #create(Session)}, but returns a {@link Login} + * that is ready to be used. * * @param session - * {@link Session} to be used for registration + * {@link Session} to be used for registration * @return {@link Login} referring to the new account */ public Login createLogin(Session session) throws AcmeException { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java index 6823ba05..4b95264d 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeJsonResource.java @@ -25,7 +25,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * An ACME resource that stores its state in a JSON structure. + * An extension of {@link AcmeResource} that also contains the current state of a resource + * as JSON document. If the current state is not present, this class takes care of + * fetching it from the server if necessary. */ public abstract class AcmeJsonResource extends AcmeResource { private static final long serialVersionUID = -5060364275766082345L; @@ -53,6 +55,9 @@ public abstract class AcmeJsonResource extends AcmeResource { * This method can be used to read proprietary data from the resources. * * @return Resource data, as {@link JSON}. + * @throws AcmeLazyLoadingException + * if an {@link AcmeException} occured while fetching the current state from + * the server. */ public JSON getJSON() { if (data == null) { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeResource.java b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeResource.java index 4e320b3a..4012a34a 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeResource.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/AcmeResource.java @@ -20,7 +20,12 @@ import java.util.Objects; import edu.umd.cs.findbugs.annotations.Nullable; /** - * A generic ACME resource. + * This is the root class of all ACME resources (like accounts, orders, certificates). + * Every resource is identified by its location URL. + *

+ * This class also takes care for proper serialization and de-serialization of the + * resource. After de-serialization, the resource must be bound to a {@link Login} again, + * using {@link #rebind(Login)}. */ public abstract class AcmeResource implements Serializable { private static final long serialVersionUID = -7930580802257379731L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java index c9f33e30..c0629b5e 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java @@ -37,10 +37,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Represents a certificate and its certificate chain. + * Represents an issued certificate and its certificate chain. *

- * Note that a certificate is immutable once it is issued. For renewal, a new certificate - * must be ordered. + * A certificate is immutable once it is issued. For renewal, a new certificate must be + * ordered. */ public class Certificate extends AcmeResource { private static final long serialVersionUID = 7381527770159084201L; @@ -56,12 +56,12 @@ public class Certificate extends AcmeResource { /** * Downloads the certificate chain. *

- * The certificate is downloaded lazily by the other methods. So usually there is no - * need to invoke this method, unless the download is to be enforced. If the - * certificate has been downloaded already, nothing will happen. + * The certificate is downloaded lazily by the other methods. Usually there is no need + * to invoke this method, unless the download is to be enforced. If the certificate + * has been downloaded already, nothing will happen. * * @throws AcmeException - * if the certificate could not be downloaded + * if the certificate could not be downloaded */ public void download() throws AcmeException { if (certChain == null) { @@ -125,7 +125,7 @@ public class Certificate extends AcmeResource { /** * Writes the certificate to the given writer. It is written in PEM format, with the - * end-entity cert coming first, followed by the intermediate ceritificates. + * end-entity cert coming first, followed by the intermediate certificates. * * @param out * {@link Writer} to write to. The writer is not closed after use. @@ -154,23 +154,28 @@ public class Certificate extends AcmeResource { * {@link RevocationReason} stating the reason of the revocation that is * used when generating OCSP responses and CRLs. {@code null} to give no * reason. + * @see #revoke(Login, X509Certificate, RevocationReason) + * @see #revoke(Session, KeyPair, X509Certificate, RevocationReason) */ public void revoke(@Nullable RevocationReason reason) throws AcmeException { revoke(getLogin(), getCertificate(), reason); } /** - * Revoke a certificate. This call is meant to be used for revoking certificates if - * only the account's key pair and the certificate itself is available. + * Revoke a certificate. + *

+ * Use this method if the certificate's location is unknown, so you cannot regenerate + * a {@link Certificate} instance. This method requires a {@link Login} to your + * account and the issued certificate. * * @param login - * {@link Login} to the account + * {@link Login} to the account * @param cert - * The {@link X509Certificate} to be revoked + * The {@link X509Certificate} to be revoked * @param reason - * {@link RevocationReason} stating the reason of the revocation that is - * used when generating OCSP responses and CRLs. {@code null} to give no - * reason. + * {@link RevocationReason} stating the reason of the revocation that is used + * when generating OCSP responses and CRLs. {@code null} to give no reason. + * @see #revoke(Session, KeyPair, X509Certificate, RevocationReason) * @since 2.6 */ public static void revoke(Login login, X509Certificate cert, @Nullable RevocationReason reason) @@ -195,19 +200,22 @@ public class Certificate extends AcmeResource { } /** - * Revoke a certificate. This call is meant to be used for revoking certificates if - * the account's key pair was lost. + * Revoke a certificate. + *

+ * Use this method if the key pair of your account was lost (so you are unable to + * login into your account), but you still have the key pair of the affected domain + * and the issued certificate. * * @param session - * {@link Session} connected to the ACME server + * {@link Session} connected to the ACME server * @param domainKeyPair - * Key pair the CSR was signed with + * Key pair the CSR was signed with * @param cert - * The {@link X509Certificate} to be revoked + * The {@link X509Certificate} to be revoked * @param reason - * {@link RevocationReason} stating the reason of the revocation that is - * used when generating OCSP responses and CRLs. {@code null} to give no - * reason. + * {@link RevocationReason} stating the reason of the revocation that is used + * when generating OCSP responses and CRLs. {@code null} to give no reason. + * @see #revoke(Login, X509Certificate, RevocationReason) */ public static void revoke(Session session, KeyPair domainKeyPair, X509Certificate cert, @Nullable RevocationReason reason) throws AcmeException { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java index a372e63f..87bed6ac 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Identifier.java @@ -31,7 +31,7 @@ import org.shredzone.acme4j.toolbox.JSONBuilder; * The ACME protocol only defines the DNS identifier, which identifies a domain name. * acme4j also supports IP identifiers. *

- * CAs may define further, proprietary identifier types. + * CAs, and other acme4j modules, may define further, proprietary identifier types. * * @since 2.3 */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Login.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Login.java index e6cc5c45..d0acdb96 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Login.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Login.java @@ -26,12 +26,22 @@ import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.toolbox.JSON; /** - * A {@link Login} is a {@link Session} that is connected to an {@link Account} at the - * ACME server. It contains the account's {@link KeyPair} and the {@link URL} of the - * account. + * A {@link Login} into an account. *

- * Note that {@link Login} objects are not serializable, as they contain a keypair and - * volatile data. + * A login is bound to a {@link Session}. However, a {@link Session} can handle multiple + * logins in parallel. + *

+ * To create a login, you need to specify the location URI of the {@link Account}, and + * need to provide the {@link KeyPair} the account was created with. If the account's + * location URL is unknown, the account can be re-registered with the + * {@link AccountBuilder}, using {@link AccountBuilder#onlyExisting()} to make sure that + * no new account will be created. If the key pair was lost though, there is no automatic + * way to regain access to your account, and you have to contact your CA's support hotline + * for assistance. + *

+ * Note that {@link Login} objects are intentionally not serializable, as they contain a + * keypair and volatile data. On distributed systems, you can create a {@link Login} to + * the same account for every service instance. */ public class Login { @@ -88,10 +98,11 @@ public class Login { } /** - * Creates a new instance of {@link Authorization} and binds it to this login. + * Creates a new instance of an existing {@link Authorization} and binds it to this + * login. * * @param location - * Location of the Authorization + * Location of the Authorization * @return {@link Authorization} bound to the login */ public Authorization bindAuthorization(URL location) { @@ -99,10 +110,11 @@ public class Login { } /** - * Creates a new instance of {@link Certificate} and binds it to this login. + * Creates a new instance of an existing {@link Certificate} and binds it to this + * login. * * @param location - * Location of the Certificate + * Location of the Certificate * @return {@link Certificate} bound to the login */ public Certificate bindCertificate(URL location) { @@ -110,10 +122,10 @@ public class Login { } /** - * Creates a new instance of {@link Order} and binds it to this login. + * Creates a new instance of an existing {@link Order} and binds it to this login. * * @param location - * Location URL of the order + * Location URL of the order * @return {@link Order} bound to the login */ public Order bindOrder(URL location) { @@ -121,12 +133,14 @@ public class Login { } /** - * Creates a new instance of {@link Challenge} and binds it to this login. + * Creates a new instance of an existing {@link Challenge} and binds it to this + * login. Use this method only if the resulting challenge type is unknown. * * @param location - * Location URL of the challenge + * Location URL of the challenge * @return {@link Challenge} bound to the login * @since 2.8 + * @see #bindChallenge(URL, Class) */ public Challenge bindChallenge(URL location) { try (var connect = session.connect()) { @@ -138,7 +152,8 @@ public class Login { } /** - * Creates a new instance of a challenge and binds it to this login. + * Creates a new instance of an existing {@link Challenge} and binds it to this + * login. Use this method if the resulting challenge type is known. * * @param location * Location URL of the challenge @@ -175,7 +190,8 @@ public class Login { } /** - * Sets a different {@link KeyPair}. + * Sets a different {@link KeyPair}. The new key pair is only used locally in this + * instance, but is not set on server side! */ protected void setKeyPair(KeyPair keyPair) { this.keyPair = Objects.requireNonNull(keyPair, "keyPair"); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Metadata.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Metadata.java index 323124bb..93c7cde3 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Metadata.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Metadata.java @@ -25,7 +25,7 @@ import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON.Value; /** - * Contains metadata related to the provider. + * A collection of metadata related to the CA provider. */ public class Metadata { @@ -42,7 +42,7 @@ public class Metadata { } /** - * Returns an {@link URI} to the current terms of service, or {@code null} if not + * Returns an {@link URI} of the current terms of service, or {@code null} if not * available. */ @Nullable @@ -51,7 +51,7 @@ public class Metadata { } /** - * Returns an {@link URL} to a website providing more information about the ACME + * Returns an {@link URL} of a website providing more information about the ACME * server. {@code null} if not available. */ @Nullable @@ -79,7 +79,7 @@ public class Metadata { } /** - * Returns whether the CA supports short-term auto renewal of certificates. + * Returns whether the CA supports short-term auto-renewal of certificates. * * @since 2.3 */ @@ -89,8 +89,8 @@ public class Metadata { /** * Returns the minimum acceptable value for the maximum validity of a certificate - * before auto renewal. {@code null} if the CA does not support short-term auto - * renewal. + * before auto-renewal. {@code null} if the CA does not support short-term + * auto-renewal. * * @since 2.3 */ @@ -105,7 +105,7 @@ public class Metadata { /** * Returns the maximum delta between auto-renewal end date and auto-renewal start - * date. {@code null} if the CA does not support short-term auto renewal. + * date. {@code null} if the CA does not support short-term auto-renewal. * * @since 2.3 */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java index c16afa12..54c00cdd 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Represents a certificate order. + * A representation of a certificate order at the CA. */ public class Order extends AcmeJsonResource { private static final long serialVersionUID = 5435808648658292177L; @@ -50,7 +50,7 @@ public class Order extends AcmeJsonResource { } /** - * Returns a {@link Problem} document if the order failed. + * Returns a {@link Problem} document with the reason if the order has failed. */ @Nullable public Problem getError() { @@ -58,7 +58,8 @@ public class Order extends AcmeJsonResource { } /** - * Gets the expiry date of the authorization, if set by the server. + * Gets the expiry date of the authorization, if set by the server, {@code null} + * otherwise. */ @Nullable public Instant getExpires() { @@ -66,7 +67,7 @@ public class Order extends AcmeJsonResource { } /** - * Gets the list of {@link Identifier} to be ordered. + * Gets a list of {@link Identifier} that are connected to this order. * * @since 2.3 */ @@ -95,7 +96,8 @@ public class Order extends AcmeJsonResource { } /** - * Gets the {@link Authorization} required for this order, in no specific order. + * Gets the {@link Authorization} that are required to fulfil this order, in no + * specific order. */ public List getAuthorizations() { var login = getLogin(); @@ -148,12 +150,12 @@ public class Order extends AcmeJsonResource { * {@link #getCertificate()}. *

* Even though the ACME protocol uses the term "finalize an order", this method is - * called {@link #execute(byte[])} to avoid confusion with the general + * called {@link #execute(byte[])} to avoid confusion with the problematic * {@link Object#finalize()} method. * * @param csr - * CSR containing the parameters for the certificate being requested, in - * DER format + * CSR containing the parameters for the certificate being requested, in DER + * format */ public void execute(byte[] csr) throws AcmeException { LOG.debug("finalize"); @@ -231,7 +233,7 @@ public class Order extends AcmeJsonResource { } /** - * Returns the predate period of each certificate, or {@code null}. + * Returns the pre-date period of each certificate, or {@code null}. * * @since 2.7 */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java index 78a1d1f5..eed445c3 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/OrderBuilder.java @@ -31,7 +31,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * A builder for a new {@link Order} object. + * Start a new certificate {@link Order}. + *

+ * Use {@link Account#newOrder()} to create a new {@link OrderBuilder} instance. */ public class OrderBuilder { private static final Logger LOG = LoggerFactory.getLogger(OrderBuilder.class); @@ -155,18 +157,17 @@ public class OrderBuilder { } /** - * Enables short-term automatic renewal of the certificate. Must be supported by the - * CA. + * Enables short-term automatic renewal of the certificate, if supported by the CA. *

- * Automatic renewals cannot be combined with {@link #notBefore(Instant)} or {@link - * #notAfter(Instant)}. + * Automatic renewals cannot be combined with {@link #notBefore(Instant)} or + * {@link #notAfter(Instant)}. * * @return itself * @since 2.3 */ public OrderBuilder autoRenewal() { if (notBefore != null || notAfter != null) { - throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewalOr"); + throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewal"); } this.autoRenewal = true; return this; @@ -249,7 +250,8 @@ public class OrderBuilder { * order for this option to work. *

* This option is only needed if you plan to fetch the STAR certificate via other - * means than by using acme4j. + * means than by using acme4j. acme4j is fetching certificates via POST-as-GET + * request. *

* Implies {@link #autoRenewal()}. * diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java index e7766ba8..457f79ba 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Problem.java @@ -27,7 +27,8 @@ import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON.Value; /** - * Represents a JSON Problem. + * A JSON problem. It contains further, machine- and human-readable details about the + * reason of an error or failure. * * @see RFC 7807 */ @@ -89,7 +90,7 @@ public class Problem implements Serializable { } /** - * Returns an URI that identifies the specific occurence of the problem. It is always + * Returns a URI that identifies the specific occurence of the problem. It is always * an absolute URI. */ @Nullable @@ -131,7 +132,7 @@ public class Problem implements Serializable { } /** - * Returns the problem as {@link JSON} object, to access other fields. + * Returns the problem as {@link JSON} object, to access other, non-standard fields. * * @return Problem as {@link JSON} object */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/RevocationReason.java b/acme4j-client/src/main/java/org/shredzone/acme4j/RevocationReason.java index 399c8674..e99ed5cf 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/RevocationReason.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/RevocationReason.java @@ -18,10 +18,10 @@ import java.util.Arrays; import edu.umd.cs.findbugs.annotations.Nullable; /** - * Enumeration of revocation reasons. + * An enumeration of revocation reasons. * * @see RFC 5280 Section - * 5.3.1 + * 5.3.1 */ public enum RevocationReason { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java index 3ffd51eb..b6a9b039 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java @@ -37,7 +37,12 @@ import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON.Value; /** - * A session stores the ACME server URI. It also tracks communication parameters. + * A {@link Session} tracks the entire communication with a CA. + *

+ * To create a session instance, use its constructor. It requires the URI of the ACME + * server to connect to. This can be the location of the CA's directory (via {@code http} + * or {@code https} protocol), or a special URI (via {@code acme} protocol). See the + * documentation about valid URIs. */ public class Session { @@ -59,7 +64,11 @@ public class Session { * Creates a new {@link Session}. * * @param serverUri - * URI string of the ACME server + * URI string of the ACME server to connect to. This is either the location of + * the CA's ACME directory (using {@code http} or {@code https} protocol), or + * a special URI (using the {@code acme} protocol). + * @throws IllegalArgumentException + * if no ACME provider was found for the server URI. */ public Session(String serverUri) { this(URI.create(serverUri)); @@ -69,9 +78,11 @@ public class Session { * Creates a new {@link Session}. * * @param serverUri - * {@link URI} of the ACME server + * {@link URI} of the ACME server to connect to. This is either the location + * of the CA's ACME directory (using {@code http} or {@code https} protocol), + * or a special URI (using the {@code acme} protocol). * @throws IllegalArgumentException - * if no ACME provider was found for the server URI. + * if no ACME provider was found for the server URI. */ public Session(URI serverUri) { this.serverUri = Objects.requireNonNull(serverUri, "serverUri"); @@ -96,7 +107,7 @@ public class Session { /** * Creates a new {@link Session} using the given {@link AcmeProvider}. *

- * This constructor should only be used for testing purposes. + * This constructor is only to be used for testing purposes. * * @param serverUri * {@link URI} of the ACME server @@ -134,7 +145,8 @@ public class Session { } /** - * Gets the last base64 encoded nonce, or {@code null} if the session is new. + * Gets the last base64 encoded nonce, or {@code null} if the session is new. This + * method is mainly for internal use. */ @Nullable public String getNonce() { @@ -142,7 +154,8 @@ public class Session { } /** - * Sets the base64 encoded nonce received by the server. + * Sets the base64 encoded nonce received by the server. This method is mainly for + * internal use. */ public void setNonce(@Nullable String nonce) { this.nonce = nonce; @@ -160,8 +173,8 @@ public class Session { /** * Sets the locale used in this session. The locale is passed to the server as * Accept-Language header. The server may respond with localized messages. - * The default is the system's language. If set to {@code null}, no special language - * is selected. + * The default is the system's language. If set to {@code null}, any language will be + * accepted. */ public void setLocale(@Nullable Locale locale) { this.locale = locale; @@ -169,7 +182,8 @@ public class Session { } /** - * Gets an Accept-Language header value that matches the current locale. + * Gets an Accept-Language header value that matches the current locale. This method + * is mainly for internal use. * * @since 3.0.0 */ @@ -207,7 +221,7 @@ public class Session { /** * Gets the {@link URL} of the given {@link Resource}. This may involve connecting to - * the server and getting a directory. The result is cached. + * the server and fetching the directory. The result is cached. * * @param resource * {@link Resource} to get the {@link URL} of @@ -226,7 +240,7 @@ public class Session { /** * Gets the metadata of the provider's directory. This may involve connecting to the - * server and getting a directory. The result is cached. + * server and fetching the directory. The result is cached. * * @return {@link Metadata}. May contain no data, but is never {@code null}. */ @@ -287,8 +301,8 @@ public class Session { } /** - * Returns {@code true} if a directory is available. Should only be invoked by {@link - * AcmeProvider} implementations. + * Returns {@code true} if a copy of the directory is present in a local cache. It is + * not evaluated if the cached copy has expired though. * * @return {@code true} if a directory is available. * @since 2.10 diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java index e1c395b3..86101bde 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Status.java @@ -16,7 +16,7 @@ package org.shredzone.acme4j; import java.util.Arrays; /** - * Status codes of challenges and authorizations. + * An enumeration of status codes of challenges and authorizations. */ public enum Status { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java index 2641f123..8e3e3475 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Challenge.java @@ -33,9 +33,9 @@ import org.slf4j.LoggerFactory; * implementations, but it is also used if the ACME server offers a proprietary challenge * that is unknown to acme4j. *

- * Subclasses must override {@link Challenge#acceptable(String)} so it only accepts the - * own type. {@link Challenge#prepareResponse(JSONBuilder)} should be overridden to put - * all required data to the response. + * Subclasses must override {@link Challenge#acceptable(String)} so it only accepts its + * own type. {@link Challenge#prepareResponse(JSONBuilder)} can be overridden to put all + * required data to the challenge response. */ public class Challenge extends AcmeJsonResource { private static final long serialVersionUID = 2338794776848388099L; @@ -72,6 +72,9 @@ public class Challenge extends AcmeJsonResource { *

* Possible values are: {@link Status#PENDING}, {@link Status#PROCESSING}, * {@link Status#VALID}, {@link Status#INVALID}. + *

+ * A challenge is only completed when it reaches either status {@link Status#VALID} or + * {@link Status#INVALID}. */ public Status getStatus() { return getJSON().get(KEY_STATUS).asStatus(); @@ -98,20 +101,25 @@ public class Challenge extends AcmeJsonResource { } /** - * Exports the response state, as preparation for triggering the challenge. + * Prepares the response message for triggering the challenge. Subclasses can add + * fields to the {@link JSONBuilder} as required by the challenge. Implementations of + * subclasses should make sure that {@link #prepareResponse(JSONBuilder)} of the + * superclass is invoked. * * @param response - * {@link JSONBuilder} to write the response to + * {@link JSONBuilder} to write the response to */ protected void prepareResponse(JSONBuilder response) { // Do nothing here... } /** - * Checks if the type is acceptable to this challenge. + * Checks if the type is acceptable to this challenge. This generic class only checks + * if the type is not blank. Subclasses should instead check if the given type matches + * expected challenge type. * * @param type - * Type to check + * Type to check * @return {@code true} if acceptable, {@code false} if not */ protected boolean acceptable(String type) { @@ -138,6 +146,16 @@ public class Challenge extends AcmeJsonResource { * Triggers this {@link Challenge}. The ACME server is requested to validate the * response. Note that the validation is performed asynchronously by the ACME server. *

+ * After a challenge is triggered, it changes to {@link Status#PENDING}. As soon as + * validation takes place, it changes to {@link Status#PROCESSING}. After validation + * the status changes to {@link Status#VALID} or {@link Status#INVALID}, depending on + * the outcome of the validation. + *

+ * If the challenge requires a resource to be set on your side (e.g. a DNS record or + * an HTTP file), it must be reachable from public before {@link #trigger()} + * is invoked, and must not be taken down until the challenge has reached + * {@link Status#VALID} or {@link Status#INVALID}. + *

* If this method is invoked a second time, the ACME server is requested to retry the * validation. This can be useful if the client state has changed, for example after a * firewall rule has been updated. diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java index c188d309..06ef297c 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Dns01Challenge.java @@ -21,7 +21,8 @@ import org.shredzone.acme4j.Login; import org.shredzone.acme4j.toolbox.JSON; /** - * Implements the {@value TYPE} challenge. + * Implements the {@value TYPE} challenge. It requires a specific DNS record for domain + * validation. See the acme4j documentation for a detailed explanation. */ public class Dns01Challenge extends TokenChallenge { private static final long serialVersionUID = 6964687027713533075L; @@ -68,9 +69,9 @@ public class Dns01Challenge extends TokenChallenge { * Creates a new generic {@link Dns01Challenge} object. * * @param login - * {@link Login} the resource is bound with + * {@link Login} the resource is bound with * @param data - * {@link JSON} challenge data + * {@link JSON} challenge data */ public Dns01Challenge(Login login, JSON data) { super(login, data); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java index 675c0a37..b2d2faf6 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/Http01Challenge.java @@ -17,7 +17,9 @@ import org.shredzone.acme4j.Login; import org.shredzone.acme4j.toolbox.JSON; /** - * Implements the {@value TYPE} challenge. + * Implements the {@value TYPE} challenge. For domain validation, it requires a specific + * file that can be retrieved from the domain via HTTP. See the acme4j documentation for a + * detailed explanation. */ public class Http01Challenge extends TokenChallenge { private static final long serialVersionUID = 3322211185872544605L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java index 8403164d..b03d8cfe 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TlsAlpn01Challenge.java @@ -19,7 +19,9 @@ import org.shredzone.acme4j.Login; import org.shredzone.acme4j.toolbox.JSON; /** - * Implements the {@value TYPE} challenge. + * Implements the {@value TYPE} challenge. It requires a specific certificate that can be + * retrieved from the domain via HTTPS request. See the acme4j documentation for a + * detailed explanation. * * @since 2.1 */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java index fdfd5b2d..6e66f54b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/TokenChallenge.java @@ -22,8 +22,8 @@ import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JoseUtils; /** - * An extension of {@link Challenge} that handles challenges with a {@code token} and - * {@code keyAuthorization}. + * A generic extension of {@link Challenge} that handles challenges with a {@code token} + * and {@code keyAuthorization}. */ public class TokenChallenge extends Challenge { private static final long serialVersionUID = 1634133407432681800L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/package-info.java index 8f4a8540..a081991b 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/package-info.java @@ -12,6 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains all standard challenges, as well as base classes for challenges + * that are proprietary to a CA. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java index 93c15875..d6b68ffc 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Connection.java @@ -32,6 +32,10 @@ import org.shredzone.acme4j.toolbox.JSONBuilder; /** * Connects to the ACME server and offers different methods for invoking the API. + *

+ * The actual way of communicating with the ACME server is intentionally left open. + * Implementations could use other means than HTTP, or could mock the communication for + * unit testing. */ public interface Connection extends AutoCloseable { @@ -132,16 +136,14 @@ public interface Connection extends AutoCloseable { throws AcmeException; /** - * Reads a server response as JSON data. + * Reads a server response as JSON object. * * @return The JSON response. - * @throws AcmeProtocolException - * if the JSON response was empty. */ JSON readJsonResponse() throws AcmeException; /** - * Reads a certificate and its issuers. + * Reads a certificate and its chain of issuers. * * @return List of X.509 certificate and chain that was read. */ @@ -193,12 +195,13 @@ public interface Connection extends AutoCloseable { Optional getExpiration(); /** - * Gets one or more relation links from the header. The result is expected to be an URL. + * Gets one or more relation links from the header. The result is expected to be a + * URL. *

* Relative links are resolved against the last request's URL. * * @param relation - * Link relation + * Link relation * @return Collection of links. Empty if there was no such relation. */ Collection getLinks(String relation); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java index 646231cd..e03bbc88 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java @@ -63,7 +63,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Default implementation of {@link Connection}. + * Default implementation of {@link Connection}. It communicates with the ACME server via + * HTTP, with a client that is provided by the given {@link HttpConnector}. */ public class DefaultConnection implements Connection { private static final Logger LOG = LoggerFactory.getLogger(DefaultConnection.class); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Resource.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Resource.java index 5e67772c..4663965a 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Resource.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/Resource.java @@ -14,7 +14,7 @@ package org.shredzone.acme4j.connector; /** - * Enumeration of resources. + * Enumeration of standard resources, and their key name in the CA's directory. */ public enum Resource { @@ -32,9 +32,9 @@ public enum Resource { } /** - * Returns the resource path. + * Returns the key name in the directory. * - * @return resource path + * @return key name */ public String path() { return path; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/package-info.java index 79d44ef6..ee6105bf 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/package-info.java @@ -12,6 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains internal classes for connection to the CA, and for handling the + * requests and responses. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java index 2a190429..a3334b06 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeException.java @@ -14,7 +14,7 @@ package org.shredzone.acme4j.exception; /** - * A generic ACME exception. + * The root class of all checked acme4j exceptions. */ public class AcmeException extends Exception { private static final long serialVersionUID = -2935088954705632025L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java index 463710bd..71e7cb87 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java @@ -20,8 +20,10 @@ import java.net.URL; import org.shredzone.acme4j.AcmeResource; /** - * This runtime exception is thrown when an {@link AcmeException} occured while trying to - * lazy-load a resource from the ACME server. + * A runtime exception that is thrown when an {@link AcmeException} occured while trying + * to lazy-load a resource from the ACME server. It contains the original cause of the + * exception and a reference to the resource that could not be lazy-loaded. It is usually + * thrown by getter methods, so the API is not polluted with checked exceptions. */ public class AcmeLazyLoadingException extends RuntimeException { private static final long serialVersionUID = 1000353433913721901L; @@ -43,6 +45,8 @@ public class AcmeLazyLoadingException extends RuntimeException { /** * Creates a new {@link AcmeLazyLoadingException}. + *

+ * This constructor is used if there is no actual instance of the resource. * * @param type * {@link AcmeResource} type to be loaded diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java index 4b124cf8..bad5ffdc 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeNetworkException.java @@ -16,8 +16,8 @@ package org.shredzone.acme4j.exception; import java.io.IOException; /** - * This exception is thrown when a network error occured while communicating with the - * server. + * A general network error has occured while communicating with the server (e.g. network + * timeout). */ public class AcmeNetworkException extends AcmeException { private static final long serialVersionUID = 2054398693543329179L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java index d4587104..c507767d 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeProtocolException.java @@ -14,8 +14,9 @@ package org.shredzone.acme4j.exception; /** - * This runtime exception is thrown on ACME protocol errors that should not occur. For - * example, this exception is thrown when a server response could not be parsed. + * A runtime exception that is thrown when the response of the server is violating the + * RFC, and could not be handled or parsed for that reason. It is an indicator that the CA + * does not fully comply with the RFC, and is usually not expected to be thrown. */ public class AcmeProtocolException extends RuntimeException { private static final long serialVersionUID = 2031203835755725193L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java index 7ea410d4..a79ac321 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRateLimitedException.java @@ -22,7 +22,9 @@ import edu.umd.cs.findbugs.annotations.Nullable; import org.shredzone.acme4j.Problem; /** - * An exception that is thrown when a rate limit was exceeded. + * A rate limit was exceeded. If provided by the server, it also includes the earliest + * time at which a new attempt will be accepted, and a reference to a document that + * further explains the rate limit that was exceeded. */ public class AcmeRateLimitedException extends AcmeServerException { private static final long serialVersionUID = 4150484059796413069L; @@ -34,12 +36,13 @@ public class AcmeRateLimitedException extends AcmeServerException { * Creates a new {@link AcmeRateLimitedException}. * * @param problem - * {@link Problem} that caused the exception + * {@link Problem} that caused the exception * @param retryAfter - * The moment the request is expected to succeed again, may be {@code null} - * if not known + * The instant of time that the request is expected to succeed again, may be + * {@code null} if not known * @param documents - * URLs pointing to documents about the rate limit that was hit + * URLs pointing to documents about the rate limit that was hit, may be + * {@code null} if not known */ public AcmeRateLimitedException(Problem problem, @Nullable Instant retryAfter, @Nullable Collection documents) { @@ -50,8 +53,8 @@ public class AcmeRateLimitedException extends AcmeServerException { } /** - * Returns the moment the request is expected to succeed again. {@code null} if this - * moment is not known. + * Returns the instant of time the request is expected to succeed again. {@code null} + * if this moment is not known. */ @Nullable public Instant getRetryAfter() { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRetryAfterException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRetryAfterException.java index 19095073..b805d603 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRetryAfterException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeRetryAfterException.java @@ -17,8 +17,8 @@ import java.time.Instant; import java.util.Objects; /** - * This exception is thrown when a server side process has not been completed yet, and the - * server returned an estimated retry date. + * A server side process has not been completed yet. The server also provides an estimate + * of when the process is expected to complete. */ public class AcmeRetryAfterException extends AcmeException { private static final long serialVersionUID = 4461979121063649905L; @@ -39,7 +39,8 @@ public class AcmeRetryAfterException extends AcmeException { } /** - * Returns the retry-after date returned by the server. + * Returns the retry-after instant returned by the server. This is only an estimate + * of when a retry attempt might succeed. */ public Instant getRetryAfter() { return retryAfter; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java index e299b692..b5589d66 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeServerException.java @@ -19,8 +19,11 @@ import java.util.Objects; import org.shredzone.acme4j.Problem; /** - * An exception that is thrown when the ACME server returned an error. It contains - * further details of the cause. + * The ACME server returned an error. The exception contains a {@link Problem} document + * containing the exact cause of the error. + *

+ * For some special cases, subclasses of this exception are thrown, so they can be handled + * individually. */ public class AcmeServerException extends AcmeException { private static final long serialVersionUID = 5971622508467042792L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java index 11d8fec8..9221d538 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUnauthorizedException.java @@ -16,8 +16,8 @@ package org.shredzone.acme4j.exception; import org.shredzone.acme4j.Problem; /** - * An exception that is thrown when the client is not authorized. The details will give - * an explanation for the reasons (e.g. "client not on a whitelist"). + * The client is not authorized to perform the operation. The {@link Problem} document + * will give further details (e.g. "client IP is blocked"). */ public class AcmeUnauthorizedException extends AcmeServerException { private static final long serialVersionUID = 9064697508262919366L; diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java index 7984cacd..432f5797 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeUserActionRequiredException.java @@ -21,7 +21,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; import org.shredzone.acme4j.Problem; /** - * An exception that is thrown when the user is required to take action as indicated. + * The user is required to take manual action as indicated. *

* Usually this exception is thrown when the terms of service have changed, and the CA * requires an agreement to the new terms before proceeding. @@ -35,9 +35,10 @@ public class AcmeUserActionRequiredException extends AcmeServerException { * Creates a new {@link AcmeUserActionRequiredException}. * * @param problem - * {@link Problem} that caused the exception + * {@link Problem} that caused the exception * @param tosUri - * {@link URI} of the terms-of-service document to accept + * {@link URI} of the terms-of-service document to accept, may be + * {@code null} */ public AcmeUserActionRequiredException(Problem problem, @Nullable URI tosUri) { super(problem); @@ -54,8 +55,8 @@ public class AcmeUserActionRequiredException extends AcmeServerException { } /** - * Returns the {@link URL} of a document that gives instructions on the actions to - * be taken by a human. + * Returns the {@link URL} of a document that gives instructions on the actions to be + * taken by a human. */ public URL getInstance() { var instance = getProblem().getInstance(); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/package-info.java index 24479702..3abcfa54 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/package-info.java @@ -12,6 +12,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains all exceptions that can be thrown by acme4j. + *

+ * {@link org.shredzone.acme4j.exception.AcmeException} is the root exception, and other + * exceptions are derived from it. + *

+ * Some methods that do lazy-loading of remote resources may throw a runtime + * {@link org.shredzone.acme4j.exception.AcmeLazyLoadingException} instead, so the API is + * not polluted with checked exceptions on every getter. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/package-info.java index aac2d503..c9f1037d 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/package-info.java @@ -12,6 +12,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * acme4j is a Java client for the ACME protocol. + *

+ * See the documentation and the example for how to use this client in your own projects. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java index 21af7dce..5e032917 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeProvider.java @@ -121,7 +121,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider { * generic {@link Challenge} or {@link TokenChallenge} instances are created. *

* Custom provider implementations may override this method to provide challenges that - * are unique to the provider. + * are proprietary to the provider. */ @Override public Challenge createChallenge(Login login, JSON data) { diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/letsencrypt/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/letsencrypt/package-info.java index 3c09a3fc..f96c1f5f 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/letsencrypt/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/letsencrypt/package-info.java @@ -12,6 +12,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains the Let's Encrypt + * {@link org.shredzone.acme4j.provider.AcmeProvider}. + * + * @see Let's Encrypt + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/package-info.java index 2e883e96..7d35f4ec 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/package-info.java @@ -12,6 +12,18 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * Acme Providers are the link between acme4j and the ACME server. They know how to + * connect to their server, and how to set up HTTP connections. + *

+ * {@link org.shredzone.acme4j.provider.AcmeProvider} is the root interface. + * {@link org.shredzone.acme4j.provider.AbstractAcmeProvider} is an abstract + * implementation of the most elementary methods. Most HTTP based providers will extend + * from {@link org.shredzone.acme4j.provider.GenericAcmeProvider} though. + *

+ * Provider implementations must be registered with Java's + * {@link java.util.ServiceLoader}. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/package-info.java index 28a876ed..bcada0a3 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/package-info.java @@ -12,6 +12,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains an {@link org.shredzone.acme4j.provider.AcmeProvider} for the + * Pebble test server. + * + * @see Pebble project page + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java index 22fcf411..9fa759c2 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/JoseUtils.java @@ -33,6 +33,9 @@ import org.slf4j.LoggerFactory; /** * Utility class that takes care of all the JOSE stuff. + *

+ * Internal class, do not use in your project! The API may change anytime, in a breaking + * manner, and without prior notice. * * @since 2.7 */ diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/package-info.java b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/package-info.java index ecc4ebff..01913ad3 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/package-info.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/toolbox/package-info.java @@ -12,6 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * Internal toolbox. The API of these classes may change anytime, in a breaking manner, + * and without prior notice. It is better not to use them in your project. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-smime/src/main/java/module-info.java b/acme4j-smime/src/main/java/module-info.java index 9a8b4c4b..df84b263 100644 --- a/acme4j-smime/src/main/java/module-info.java +++ b/acme4j-smime/src/main/java/module-info.java @@ -12,6 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This module is an add-on that provides S/MIME certificate features. + */ module org.shredzone.acme4j.smime { requires org.shredzone.acme4j; requires org.shredzone.acme4j.utils; diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00ChallengeProvider.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00ChallengeProvider.java index 6750d335..b8a98dc3 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00ChallengeProvider.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/EmailReply00ChallengeProvider.java @@ -20,7 +20,8 @@ import org.shredzone.acme4j.provider.ChallengeType; import org.shredzone.acme4j.toolbox.JSON; /** - * Generates {@link EmailReply00Challenge}. + * A provider that generates {@link EmailReply00Challenge}. It is registered as Java + * service. * * @since 2.12 */ diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/package-info.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/package-info.java index 8f24e3c2..48364de6 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/package-info.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/challenge/package-info.java @@ -12,6 +12,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains the + * {@link org.shredzone.acme4j.smime.challenge.EmailReply00Challenge#TYPE} related acme4j + * {@link org.shredzone.acme4j.challenge.Challenge} implementation. + *

+ * The {@link org.shredzone.acme4j.smime.challenge.EmailReply00ChallengeProvider} is + * registered as Java service, so acme4j is able to automatically generate + * {@link org.shredzone.acme4j.smime.challenge.EmailReply00Challenge} instances. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/csr/package-info.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/csr/package-info.java index 250c8e2c..05a63713 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/csr/package-info.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/csr/package-info.java @@ -12,6 +12,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains S/MIME CSR related utility classes. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/email/package-info.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/email/package-info.java index e621a343..1423c167 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/email/package-info.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/email/package-info.java @@ -12,6 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/** + * This package contains classes for processing incoming validation emails, and for + * generating outgoing response emails. + */ @ReturnValuesAreNonnullByDefault @DefaultAnnotationForParameters(NonNull.class) @DefaultAnnotationForFields(NonNull.class) diff --git a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java index 589f049d..843a6659 100644 --- a/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java +++ b/acme4j-smime/src/main/java/org/shredzone/acme4j/smime/exception/AcmeInvalidMessageException.java @@ -25,12 +25,12 @@ import org.bouncycastle.i18n.LocalizedException; import org.shredzone.acme4j.exception.AcmeException; /** - * This exception is thrown when the challenge message is invalid. + * This exception is thrown when the challenge email message is invalid. *

- * If this exception is thrown, the challenge message does not match the actual challenge, - * and must be rejected. + * If this exception is thrown, the challenge message does not match the actual challenge + * or has other issues. It must be rejected. *

- * Reasons may be: + * Reasons may be (for example): *