mirror of https://github.com/shred/acme4j
Use new date/time API
parent
0ed0a9219f
commit
c1b677f310
|
@ -17,11 +17,11 @@ import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
|
|||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.shredzone.acme4j.challenge.Challenge;
|
||||
|
@ -43,7 +43,7 @@ public class Authorization extends AcmeResource {
|
|||
|
||||
private String domain;
|
||||
private Status status;
|
||||
private Date expires;
|
||||
private Instant expires;
|
||||
private List<Challenge> challenges;
|
||||
private List<List<Challenge>> combinations;
|
||||
private boolean loaded = false;
|
||||
|
@ -86,7 +86,7 @@ public class Authorization extends AcmeResource {
|
|||
/**
|
||||
* Gets the expiry date of the authorization, if set by the server.
|
||||
*/
|
||||
public Date getExpires() {
|
||||
public Instant getExpires() {
|
||||
load();
|
||||
return expires;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ import java.net.HttpURLConnection;
|
|||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -234,7 +234,7 @@ public class Registration extends AcmeResource {
|
|||
* for default. May be ignored by the server.
|
||||
* @return The {@link Certificate}
|
||||
*/
|
||||
public Certificate requestCertificate(byte[] csr, Date notBefore, Date notAfter)
|
||||
public Certificate requestCertificate(byte[] csr, Instant notBefore, Instant notAfter)
|
||||
throws AcmeException {
|
||||
Objects.requireNonNull(csr, "csr");
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ package org.shredzone.acme4j;
|
|||
|
||||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -48,7 +49,7 @@ public class Session {
|
|||
private JSON directoryJson;
|
||||
private Metadata metadata;
|
||||
private Locale locale = Locale.getDefault();
|
||||
protected Date directoryCacheExpiry;
|
||||
protected Instant directoryCacheExpiry;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Session}.
|
||||
|
@ -210,10 +211,10 @@ public class Session {
|
|||
*/
|
||||
private void readDirectory() throws AcmeException {
|
||||
synchronized (this) {
|
||||
Date now = new Date();
|
||||
if (directoryJson == null || !directoryCacheExpiry.after(now)) {
|
||||
Instant now = Instant.now();
|
||||
if (directoryJson == null || !directoryCacheExpiry.isAfter(now)) {
|
||||
directoryJson = provider().directory(this, getServerUri());
|
||||
directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L);
|
||||
directoryCacheExpiry = now.plus(Duration.ofHours(1));
|
||||
|
||||
JSON meta = directoryJson.get("meta").asObject();
|
||||
if (meta != null) {
|
||||
|
|
|
@ -15,7 +15,7 @@ package org.shredzone.acme4j.challenge;
|
|||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.shredzone.acme4j.AcmeResource;
|
||||
|
@ -113,8 +113,8 @@ public class Challenge extends AcmeResource {
|
|||
/**
|
||||
* Returns the validation date, if returned by the server.
|
||||
*/
|
||||
public Date getValidated() {
|
||||
return data.get(KEY_VALIDATED).asDate();
|
||||
public Instant getValidated() {
|
||||
return data.get(KEY_VALIDATED).asInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,12 +27,13 @@ import java.security.KeyPair;
|
|||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -253,9 +254,9 @@ public class DefaultConnection implements Connection {
|
|||
|
||||
try {
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED) {
|
||||
Date retryAfter = getRetryAfterHeader();
|
||||
if (retryAfter != null) {
|
||||
throw new AcmeRetryAfterException(message, retryAfter);
|
||||
Optional<Instant> retryAfter = getRetryAfterHeader();
|
||||
if (retryAfter.isPresent()) {
|
||||
throw new AcmeRetryAfterException(message, retryAfter.get());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
|
@ -338,27 +339,29 @@ public class DefaultConnection implements Connection {
|
|||
/**
|
||||
* Gets the instant sent with the Retry-After header.
|
||||
*/
|
||||
private Date getRetryAfterHeader() {
|
||||
private Optional<Instant> getRetryAfterHeader() {
|
||||
// See RFC 2616 section 14.37
|
||||
String header = conn.getHeaderField(RETRY_AFTER_HEADER);
|
||||
if (header == null) {
|
||||
return null;
|
||||
}
|
||||
if (header != null) {
|
||||
try {
|
||||
// delta-seconds
|
||||
if (header.matches("^\\d+$")) {
|
||||
int delta = Integer.parseInt(header);
|
||||
long date = conn.getHeaderFieldDate(DATE_HEADER, System.currentTimeMillis());
|
||||
return Optional.of(Instant.ofEpochMilli(date).plusSeconds(delta));
|
||||
}
|
||||
|
||||
try {
|
||||
// delta-seconds
|
||||
if (header.matches("^\\d+$")) {
|
||||
int delta = Integer.parseInt(header);
|
||||
long date = conn.getHeaderFieldDate(DATE_HEADER, System.currentTimeMillis());
|
||||
return new Date(date + delta * 1000L);
|
||||
// HTTP-date
|
||||
long date = conn.getHeaderFieldDate(RETRY_AFTER_HEADER, 0L);
|
||||
if (date != 0) {
|
||||
return Optional.of(Instant.ofEpochMilli(date));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new AcmeProtocolException("Bad retry-after header value: " + header, ex);
|
||||
}
|
||||
|
||||
// HTTP-date
|
||||
long date = conn.getHeaderFieldDate(RETRY_AFTER_HEADER, 0L);
|
||||
return date != 0 ? new Date(date) : null;
|
||||
} catch (Exception ex) {
|
||||
throw new AcmeProtocolException("Bad retry-after header value: " + header, ex);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -386,9 +389,9 @@ public class DefaultConnection implements Connection {
|
|||
}
|
||||
|
||||
if ("rateLimited".equals(error)) {
|
||||
Date retryAfter = getRetryAfterHeader();
|
||||
Optional<Instant> retryAfter = getRetryAfterHeader();
|
||||
Collection<URI> rateLimits = getLinks("rate-limit");
|
||||
return new AcmeRateLimitExceededException(type, detail, retryAfter, rateLimits);
|
||||
return new AcmeRateLimitExceededException(type, detail, retryAfter.orElse(null), rateLimits);
|
||||
}
|
||||
|
||||
return new AcmeServerException(type, detail);
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
package org.shredzone.acme4j.exception;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* An exception that is thrown when a rate limit was exceeded.
|
||||
|
@ -24,7 +24,7 @@ import java.util.Date;
|
|||
public class AcmeRateLimitExceededException extends AcmeServerException {
|
||||
private static final long serialVersionUID = 4150484059796413069L;
|
||||
|
||||
private final Date retryAfter;
|
||||
private final Instant retryAfter;
|
||||
private final Collection<URI> documents;
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@ public class AcmeRateLimitExceededException extends AcmeServerException {
|
|||
* @param documents
|
||||
* URIs pointing to documents about the rate limit that was hit
|
||||
*/
|
||||
public AcmeRateLimitExceededException(String type, String detail, Date retryAfter, Collection<URI> documents) {
|
||||
public AcmeRateLimitExceededException(String type, String detail, Instant retryAfter, Collection<URI> documents) {
|
||||
super(type, detail);
|
||||
this.retryAfter = retryAfter;
|
||||
this.documents =
|
||||
|
@ -52,8 +52,8 @@ public class AcmeRateLimitExceededException extends AcmeServerException {
|
|||
* Returns the moment the request is expected to succeed again. {@code null} if this
|
||||
* moment is not known.
|
||||
*/
|
||||
public Date getRetryAfter() {
|
||||
return retryAfter != null ? new Date(retryAfter.getTime()) : null;
|
||||
public Instant getRetryAfter() {
|
||||
return retryAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
package org.shredzone.acme4j.exception;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,7 @@ import java.util.Objects;
|
|||
public class AcmeRetryAfterException extends AcmeException {
|
||||
private static final long serialVersionUID = 4461979121063649905L;
|
||||
|
||||
private final Date retryAfter;
|
||||
private final Instant retryAfter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeRetryAfterException}.
|
||||
|
@ -33,7 +33,7 @@ public class AcmeRetryAfterException extends AcmeException {
|
|||
* @param retryAfter
|
||||
* retry-after date returned by the server
|
||||
*/
|
||||
public AcmeRetryAfterException(String msg, Date retryAfter) {
|
||||
public AcmeRetryAfterException(String msg, Instant retryAfter) {
|
||||
super(msg);
|
||||
this.retryAfter = Objects.requireNonNull(retryAfter);
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ public class AcmeRetryAfterException extends AcmeException {
|
|||
/**
|
||||
* Returns the retry-after date returned by the server.
|
||||
*/
|
||||
public Date getRetryAfter() {
|
||||
return new Date(retryAfter.getTime());
|
||||
public Instant getRetryAfter() {
|
||||
return retryAfter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,9 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.IDN;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -164,12 +163,12 @@ public final class AcmeUtils {
|
|||
*
|
||||
* @param str
|
||||
* Date string
|
||||
* @return {@link Date} that was parsed
|
||||
* @return {@link Instant} that was parsed
|
||||
* @throws IllegalArgumentException
|
||||
* if the date string was not RFC 3339 formatted
|
||||
* @see <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</a>
|
||||
*/
|
||||
public static Date parseTimestamp(String str) {
|
||||
public static Instant parseTimestamp(String str) {
|
||||
Matcher m = DATE_PATTERN.matcher(str);
|
||||
if (!m.matches()) {
|
||||
throw new IllegalArgumentException("Illegal date: " + str);
|
||||
|
@ -198,11 +197,9 @@ public final class AcmeUtils {
|
|||
tz = TZ_PATTERN.matcher(tz).replaceAll("GMT$1$2:$3");
|
||||
}
|
||||
|
||||
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(tz));
|
||||
cal.clear();
|
||||
cal.set(year, month - 1, dom, hour, minute, second);
|
||||
cal.set(Calendar.MILLISECOND, ms);
|
||||
return cal.getTime();
|
||||
return ZonedDateTime.of(
|
||||
year, month, dom, hour, minute, second, ms * 1_000_000,
|
||||
ZoneId.of(tz)).toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,8 +27,8 @@ import java.net.MalformedURLException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -349,12 +349,11 @@ public final class JSON implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value as {@link Date}.
|
||||
* Returns the value as {@link Instant}.
|
||||
*
|
||||
* @return {@link Date}, or {@code null} if the value was not set. The returned
|
||||
* {@link Date} object is not shared and can be modified safely.
|
||||
* @return {@link Instant}, or {@code null} if the value was not set.
|
||||
*/
|
||||
public Date asDate() {
|
||||
public Instant asInstant() {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,11 @@ import static org.shredzone.acme4j.util.AcmeUtils.base64UrlEncode;
|
|||
|
||||
import java.security.Key;
|
||||
import java.security.PublicKey;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jose4j.json.JsonUtil;
|
||||
|
@ -62,25 +61,22 @@ public class JSONBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Puts a {@link Date} to the JSON. If a property with the key exists, it will be
|
||||
* Puts an {@link Instant} to the JSON. If a property with the key exists, it will be
|
||||
* replaced.
|
||||
*
|
||||
* @param key
|
||||
* Property key
|
||||
* @param value
|
||||
* Property {@link Date} value
|
||||
* Property {@link Instant} value
|
||||
* @return {@code this}
|
||||
*/
|
||||
public JSONBuilder put(String key, Date value) {
|
||||
public JSONBuilder put(String key, Instant value) {
|
||||
if (value == null) {
|
||||
put(key, (Object) null);
|
||||
return this;
|
||||
}
|
||||
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
String date = fmt.format(value);
|
||||
put(key, date);
|
||||
put(key, DateTimeFormatter.ISO_INSTANT.format(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@ import static org.shredzone.acme4j.util.TestUtils.*;
|
|||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -228,7 +229,7 @@ public class AuthorizationTest {
|
|||
*/
|
||||
@Test
|
||||
public void testUpdateRetryAfter() throws Exception {
|
||||
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
|
||||
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
|
||||
|
||||
TestableConnectionProvider provider = new TestableConnectionProvider() {
|
||||
@Override
|
||||
|
@ -250,7 +251,7 @@ public class AuthorizationTest {
|
|||
|
||||
@Override
|
||||
public void handleRetryAfter(String message) throws AcmeException {
|
||||
throw new AcmeRetryAfterException(message, new Date(retryAfter));
|
||||
throw new AcmeRetryAfterException(message, retryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -267,7 +268,7 @@ public class AuthorizationTest {
|
|||
auth.update();
|
||||
fail("Expected AcmeRetryAfterException");
|
||||
} catch (AcmeRetryAfterException ex) {
|
||||
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
|
||||
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||
}
|
||||
|
||||
assertThat(auth.getDomain(), is("example.org"));
|
||||
|
|
|
@ -22,7 +22,8 @@ import java.io.IOException;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Date;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
|
@ -107,7 +108,7 @@ public class CertificateTest {
|
|||
*/
|
||||
@Test
|
||||
public void testRetryAfter() throws AcmeException, IOException {
|
||||
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
|
||||
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
|
||||
|
||||
TestableConnectionProvider provider = new TestableConnectionProvider() {
|
||||
@Override
|
||||
|
@ -125,7 +126,7 @@ public class CertificateTest {
|
|||
|
||||
@Override
|
||||
public void handleRetryAfter(String message) throws AcmeException {
|
||||
throw new AcmeRetryAfterException(message, new Date(retryAfter));
|
||||
throw new AcmeRetryAfterException(message, retryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,7 +136,7 @@ public class CertificateTest {
|
|||
cert.download();
|
||||
fail("Expected AcmeRetryAfterException");
|
||||
} catch (AcmeRetryAfterException ex) {
|
||||
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
|
||||
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||
}
|
||||
|
||||
provider.close();
|
||||
|
|
|
@ -23,9 +23,10 @@ import java.net.HttpURLConnection;
|
|||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Iterator;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.jose4j.jws.JsonWebSignature;
|
||||
|
@ -335,15 +336,12 @@ public class RegistrationTest {
|
|||
provider.putTestResource(Resource.NEW_CERT, resourceUri);
|
||||
|
||||
byte[] csr = TestUtils.getResourceAsByteArray("/csr.der");
|
||||
Calendar notBefore = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
notBefore.clear();
|
||||
notBefore.set(2016, Calendar.JANUARY, 1);
|
||||
Calendar notAfter = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
notAfter.clear();
|
||||
notAfter.set(2016, Calendar.JANUARY, 8);
|
||||
ZoneId utc = ZoneId.of("UTC");
|
||||
Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant();
|
||||
Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant();
|
||||
|
||||
Registration registration = new Registration(provider.createSession(), locationUri);
|
||||
Certificate cert = registration.requestCertificate(csr, notBefore.getTime(), notAfter.getTime());
|
||||
Certificate cert = registration.requestCertificate(csr, notBefore, notAfter);
|
||||
|
||||
assertThat(cert.download(), is(originalCert));
|
||||
assertThat(cert.getLocation(), is(locationUri));
|
||||
|
|
|
@ -21,7 +21,7 @@ import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
@ -173,7 +173,7 @@ public class SessionTest {
|
|||
ArgumentMatchers.any(URI.class));
|
||||
|
||||
// Simulate a cache expiry
|
||||
session.directoryCacheExpiry = new Date();
|
||||
session.directoryCacheExpiry = Instant.now();
|
||||
|
||||
// Make sure directory is read once again
|
||||
assertSession(session);
|
||||
|
|
|
@ -25,7 +25,8 @@ import java.net.MalformedURLException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.jose4j.lang.JoseException;
|
||||
import org.junit.Before;
|
||||
|
@ -229,7 +230,7 @@ public class ChallengeTest {
|
|||
*/
|
||||
@Test
|
||||
public void testUpdateRetryAfter() throws Exception {
|
||||
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
|
||||
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
|
||||
|
||||
TestableConnectionProvider provider = new TestableConnectionProvider() {
|
||||
@Override
|
||||
|
@ -252,7 +253,7 @@ public class ChallengeTest {
|
|||
|
||||
@Override
|
||||
public void handleRetryAfter(String message) throws AcmeException {
|
||||
throw new AcmeRetryAfterException(message, new Date(retryAfter));
|
||||
throw new AcmeRetryAfterException(message, retryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -265,7 +266,7 @@ public class ChallengeTest {
|
|||
challenge.update();
|
||||
fail("Expected AcmeRetryAfterException");
|
||||
} catch (AcmeRetryAfterException ex) {
|
||||
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
|
||||
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||
}
|
||||
|
||||
assertThat(challenge.getStatus(), is(Status.VALID));
|
||||
|
|
|
@ -25,9 +25,10 @@ import java.net.HttpURLConnection;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -254,12 +255,12 @@ public class DefaultConnectionTest {
|
|||
*/
|
||||
@Test
|
||||
public void testHandleRetryAfterHeaderDate() throws AcmeException, IOException {
|
||||
Date retryDate = new Date(System.currentTimeMillis() + 10 * 60 * 60 * 1000L);
|
||||
Instant retryDate = Instant.now().plus(Duration.ofHours(10));
|
||||
String retryMsg = "absolute date";
|
||||
|
||||
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_ACCEPTED);
|
||||
when(mockUrlConnection.getHeaderField("Retry-After")).thenReturn(retryDate.toString());
|
||||
when(mockUrlConnection.getHeaderFieldDate("Retry-After", 0L)).thenReturn(retryDate.getTime());
|
||||
when(mockUrlConnection.getHeaderFieldDate("Retry-After", 0L)).thenReturn(retryDate.toEpochMilli());
|
||||
|
||||
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
|
||||
conn.conn = mockUrlConnection;
|
||||
|
@ -297,7 +298,7 @@ public class DefaultConnectionTest {
|
|||
conn.handleRetryAfter(retryMsg);
|
||||
fail("no AcmeRetryAfterException was thrown");
|
||||
} catch (AcmeRetryAfterException ex) {
|
||||
assertThat(ex.getRetryAfter(), is(new Date(now + delta * 1000L)));
|
||||
assertThat(ex.getRetryAfter(), is(Instant.ofEpochMilli(now).plusSeconds(delta)));
|
||||
assertThat(ex.getMessage(), is(retryMsg));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@ import static org.hamcrest.Matchers.*;
|
|||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -35,7 +36,7 @@ public class AcmeRateLimitExceededExceptionTest {
|
|||
public void testAcmeRateLimitExceededException() {
|
||||
String type = "urn:ietf:params:acme:error:rateLimited";
|
||||
String detail = "Too many requests per minute";
|
||||
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
|
||||
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
|
||||
Collection<URI> documents = Arrays.asList(
|
||||
URI.create("http://example.com/doc1.html"),
|
||||
URI.create("http://example.com/doc2.html"));
|
||||
|
|
|
@ -16,7 +16,8 @@ package org.shredzone.acme4j.exception;
|
|||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -31,16 +32,12 @@ public class AcmeRetryAfterExceptionTest {
|
|||
@Test
|
||||
public void testAcmeRetryAfterException() {
|
||||
String detail = "Too early";
|
||||
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
|
||||
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
|
||||
|
||||
AcmeRetryAfterException ex
|
||||
= new AcmeRetryAfterException(detail, retryAfter);
|
||||
AcmeRetryAfterException ex = new AcmeRetryAfterException(detail, retryAfter);
|
||||
|
||||
assertThat(ex.getMessage(), is(detail));
|
||||
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||
|
||||
// make sure we get a copy of the Date object
|
||||
assertThat(ex.getRetryAfter(), not(sameInstance(retryAfter)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,16 +45,12 @@ public class AcmeRetryAfterExceptionTest {
|
|||
*/
|
||||
@Test
|
||||
public void testNullAcmeRetryAfterException() {
|
||||
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
|
||||
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
|
||||
|
||||
AcmeRetryAfterException ex
|
||||
= new AcmeRetryAfterException(null, retryAfter);
|
||||
AcmeRetryAfterException ex = new AcmeRetryAfterException(null, retryAfter);
|
||||
|
||||
assertThat(ex.getMessage(), nullValue());
|
||||
assertThat(ex.getRetryAfter(), is(retryAfter));
|
||||
|
||||
// make sure we get a copy of the Date object
|
||||
assertThat(ex.getRetryAfter(), not(sameInstance(retryAfter)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,11 +21,10 @@ import java.lang.reflect.Constructor;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.security.KeyPair;
|
||||
import java.security.Security;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
|
@ -247,57 +246,55 @@ public class AcmeUtilsTest {
|
|||
/**
|
||||
* Matches the given time.
|
||||
*/
|
||||
private DateMatcher isDate(int year, int month, int dom, int hour, int minute, int second) {
|
||||
private InstantMatcher isDate(int year, int month, int dom, int hour, int minute, int second) {
|
||||
return isDate(year, month, dom, hour, minute, second, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the given time and milliseconds.
|
||||
*/
|
||||
private DateMatcher isDate(int year, int month, int dom, int hour, int minute, int second, int ms) {
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
cal.clear();
|
||||
cal.set(year, month - 1, dom, hour, minute, second);
|
||||
cal.set(Calendar.MILLISECOND, ms);
|
||||
return new DateMatcher(cal);
|
||||
private InstantMatcher isDate(int year, int month, int dom, int hour, int minute, int second, int ms) {
|
||||
Instant cmp = ZonedDateTime.of(
|
||||
year, month, dom, hour, minute, second, ms * 1_000_000,
|
||||
ZoneId.of("UTC")).toInstant();
|
||||
return new InstantMatcher(cmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date matcher that gives a readable output on mismatch.
|
||||
*/
|
||||
private static class DateMatcher extends BaseMatcher<Date> {
|
||||
private final Calendar cal;
|
||||
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
|
||||
private static class InstantMatcher extends BaseMatcher<Instant> {
|
||||
private final Instant cmp;
|
||||
private final DateTimeFormatter dtf = DateTimeFormatter.ISO_INSTANT;
|
||||
|
||||
public DateMatcher(Calendar cal) {
|
||||
this.cal = cal;
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
public InstantMatcher(Instant cmp) {
|
||||
this.cmp = cmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (!(item instanceof Date)) {
|
||||
if (!(item instanceof Instant)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date date = (Date) item;
|
||||
return date.equals(cal.getTime());
|
||||
Instant date = (Instant) item;
|
||||
return date.equals(cmp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(sdf.format(cal.getTime()));
|
||||
description.appendValue(dtf.format(cmp));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
if (!(item instanceof Date)) {
|
||||
description.appendText("is not a Date");
|
||||
if (!(item instanceof Instant)) {
|
||||
description.appendText("is not an Instant");
|
||||
return;
|
||||
}
|
||||
|
||||
Date date = (Date) item;
|
||||
description.appendText("was ").appendValue(sdf.format(date));
|
||||
Instant date = (Instant) item;
|
||||
description.appendText("was ").appendValue(dtf.format(date));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ import static org.junit.Assert.assertThat;
|
|||
import java.io.IOException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.jose4j.json.JsonUtil;
|
||||
import org.jose4j.lang.JoseException;
|
||||
|
@ -81,13 +81,11 @@ public class JSONBuilderTest {
|
|||
*/
|
||||
@Test
|
||||
public void testDate() {
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+2"));
|
||||
cal.clear();
|
||||
cal.set(2016, Calendar.JUNE, 1, 5, 13, 46);
|
||||
Instant date = ZonedDateTime.of(2016, 6, 1, 5, 13, 46, 0, ZoneId.of("GMT+2")).toInstant();
|
||||
|
||||
JSONBuilder cb = new JSONBuilder();
|
||||
cb.put("fooDate", cal.getTime());
|
||||
cb.put("fooNull", (Date) null);
|
||||
cb.put("fooDate", date);
|
||||
cb.put("fooNull", (Instant) null);
|
||||
|
||||
assertThat(cb.toString(), is("{\"fooDate\":\"2016-06-01T03:13:46Z\",\"fooNull\":null}"));
|
||||
}
|
||||
|
|
|
@ -26,10 +26,11 @@ import java.io.ObjectOutputStream;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
@ -145,9 +146,7 @@ public class JSONTest {
|
|||
*/
|
||||
@Test
|
||||
public void testGetter() throws MalformedURLException {
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
cal.clear();
|
||||
cal.set(2016, 0, 8);
|
||||
Instant date = LocalDate.of(2016, 1, 8).atStartOfDay(ZoneId.of("UTC")).toInstant();
|
||||
|
||||
JSON json = TestUtils.getJsonAsObject("json");
|
||||
|
||||
|
@ -155,7 +154,7 @@ public class JSONTest {
|
|||
assertThat(json.get("number").asInt(), is(123));
|
||||
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
|
||||
assertThat(json.get("url").asURL(), is(new URL("http://example.com")));
|
||||
assertThat(json.get("date").asDate(), is(cal.getTime()));
|
||||
assertThat(json.get("date").asInstant(), is(date));
|
||||
|
||||
JSON.Array array = json.get("array").asArray();
|
||||
assertThat(array.get(0).asString(), is("foo"));
|
||||
|
@ -181,7 +180,7 @@ public class JSONTest {
|
|||
assertThat(json.get("none").asString(), is(nullValue()));
|
||||
assertThat(json.get("none").asURI(), is(nullValue()));
|
||||
assertThat(json.get("none").asURL(), is(nullValue()));
|
||||
assertThat(json.get("none").asDate(), is(nullValue()));
|
||||
assertThat(json.get("none").asInstant(), is(nullValue()));
|
||||
assertThat(json.get("none").asArray(), is(nullValue()));
|
||||
assertThat(json.get("none").asObject(), is(nullValue()));
|
||||
|
||||
|
@ -246,7 +245,7 @@ public class JSONTest {
|
|||
}
|
||||
|
||||
try {
|
||||
json.get("text").asDate();
|
||||
json.get("text").asInstant();
|
||||
fail("no exception was thrown");
|
||||
} catch (AcmeProtocolException ex) {
|
||||
// expected
|
||||
|
|
|
@ -25,6 +25,8 @@ import java.security.KeyPair;
|
|||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
|
@ -212,17 +214,17 @@ public final class CertificateUtils {
|
|||
*/
|
||||
private static X509Certificate createCertificate(KeyPair keypair, String... subject) throws IOException {
|
||||
final long now = System.currentTimeMillis();
|
||||
final long validSpanMs = 7 * 24 * 60 * 60 * 1000L;
|
||||
final String signatureAlg = "SHA256withRSA";
|
||||
|
||||
try {
|
||||
X500Name issuer = new X500Name("CN=acme.invalid");
|
||||
BigInteger serial = BigInteger.valueOf(now);
|
||||
Date notBefore = new Date(now);
|
||||
Date notAfter = new Date(now + validSpanMs);
|
||||
Instant notBefore = Instant.ofEpochMilli(now);
|
||||
Instant notAfter = notBefore.plus(Duration.ofDays(7));
|
||||
|
||||
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
|
||||
issuer, serial, notBefore, notAfter, issuer, keypair.getPublic());
|
||||
issuer, serial, Date.from(notBefore), Date.from(notAfter),
|
||||
issuer, keypair.getPublic());
|
||||
|
||||
GeneralName[] gns = new GeneralName[subject.length];
|
||||
for (int ix = 0; ix < subject.length; ix++) {
|
||||
|
|
|
@ -28,6 +28,8 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -132,13 +134,13 @@ public class CertificateUtilsTest {
|
|||
|
||||
X509Certificate cert = CertificateUtils.createTlsSniCertificate(keypair, subject);
|
||||
|
||||
Date now = new Date();
|
||||
Date end = new Date(now.getTime() + (8 * 24 * 60 * 60 * 1000L));
|
||||
Instant now = Instant.now();
|
||||
Instant end = now.plus(Duration.ofDays(8));
|
||||
|
||||
assertThat(cert, not(nullValue()));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(now)));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(end)));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(now)));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
|
||||
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
|
||||
assertThat(getSANs(cert), containsInAnyOrder(subject));
|
||||
}
|
||||
|
@ -156,13 +158,13 @@ public class CertificateUtilsTest {
|
|||
|
||||
X509Certificate cert = CertificateUtils.createTlsSni02Certificate(keypair, sanA, sanB);
|
||||
|
||||
Date now = new Date();
|
||||
Date end = new Date(now.getTime() + (8 * 24 * 60 * 60 * 1000L));
|
||||
Instant now = Instant.now();
|
||||
Instant end = now.plus(Duration.ofDays(8));
|
||||
|
||||
assertThat(cert, not(nullValue()));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(now)));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(end)));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(now)));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
|
||||
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
|
||||
assertThat(getSANs(cert), containsInAnyOrder(sanA, sanB));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue