Attention une mise à jour du service Gitlab va être effectuée le mardi 14 décembre entre 13h30 et 14h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes.

Commit 1fb4e89e authored by avocatier tac's avatar avocatier tac Committed by calocedre TAC
Browse files

fixing Location.newDeepLink(periodStartTime) that would fire a...

fixing Location.newDeepLink(periodStartTime) that would fire a StackOverflowError because of an infinite recursion
parent 848f7cc7
......@@ -58,6 +58,12 @@
<version>3.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
......
......@@ -50,7 +50,7 @@ public class Location {
*/
public String newDeepLink(int periodStartTime) throws CleaEncryptionException {
// QR-code validity starts at period start time
return this.newDeepLink(periodStartTime * TimeUtils.NB_SECONDS_PER_HOUR);
return this.newDeepLink(periodStartTime, periodStartTime);
}
/**
......@@ -101,6 +101,9 @@ public class Location {
this.locationSpecificPart.setPeriodStartTime(periodStartTime);
this.locationSpecificPart.setLocationTemporarySecretKey(locationTemporarySecretKey);
this.locationSpecificPart.setLocationTemporaryPublicId(currentLocationTemporaryPublicId);
if (Objects.nonNull(this.contact)) {
this.contact.setPeriodStartTime(periodStartTime);
}
log.debug("new periodStartTime: {} ", Integer.toUnsignedString(periodStartTime));
log.debug("locationTemporarySecretKey*: {}*", BytesUtils.bytesToString(locationTemporarySecretKey));
log.debug("locationTemporaryPublicID: " + currentLocationTemporaryPublicId.toString());
......@@ -112,12 +115,21 @@ public class Location {
log.warn("Cannot update QrCode validity start time. No renewal specified!");
return;
}
if(qrCodeValidityStartTime < periodStartTime){
log.warn("Cannot set QrCode validity start time to {}. It preceeds period validity (start: {}, duration (in hours): {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getPeriodDuration());
return;
}
if (qrCodeValidityStartTime > periodStartTime + this.locationSpecificPart.getPeriodDuration() * TimeUtils.NB_SECONDS_PER_HOUR) {
log.warn("Cannot set QrCode validity start time to {}. It exceeds period validity (start: {}, duration (in hours): {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getPeriodDuration());
return;
}
if (((qrCodeValidityStartTime - periodStartTime) % this.locationSpecificPart.getQrCodeRenewalInterval()) != 0) {
if ((this.locationSpecificPart.getQrCodeRenewalInterval() != 0) &&
(((qrCodeValidityStartTime - periodStartTime) % this.locationSpecificPart.getQrCodeRenewalInterval()) != 0)) {
log.warn("Cannot set QrCode validity start time to {}. It is not a multiple of qrCodeRenewalInterval (qrCodeValidityStartTime: {}, periodStartTime: {}, qrCodeRenewalInterval: {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getQrCodeRenewalInterval());
return;
......
......@@ -5,7 +5,9 @@ import javax.validation.constraints.Max;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.AccessLevel;
@Builder
@Getter
......@@ -18,5 +20,6 @@ public class LocationContact {
@Max(value = 6)
String locationPin;
/* Starting time of the period in seconds */
@Setter(AccessLevel.PROTECTED)
int periodStartTime;
}
......@@ -24,7 +24,7 @@ public class TimeUtils {
}
/**
* Get timestamp rounded to the closest hour.
* Get NTP UTC timestamp rounded to the closest hour.
* @param timestamp the timestamp in seconds
* @return the rounded timestamp
*/
......@@ -32,16 +32,34 @@ public class TimeUtils {
long timestampPlusHalfTimeRounding = timestamp + NB_SECONDS_PER_HOUR/2;
return timestampPlusHalfTimeRounding - (timestampPlusHalfTimeRounding % NB_SECONDS_PER_HOUR);
}
/**
* Get NTP UTC timestamp rounded to the closest hour from an Instant
* @param instant timestamp as an Instant
* @return rounded timestamp
*/
public static long hourRoundedTimestampFromInstant(Instant instant){
return hourRoundedTimestamp(instant.getEpochSecond() + SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
/**
* Get NTP UTC timestamp rounded to the closest hour from an Instant limited to 32 bits (java int)
* @param instant timestamp as an Instant
* @return rounded timestamp limited to 32 bits (java int)
*/
public static int hourRoundedTimestamp32FromInstant(Instant instant){
return (int) hourRoundedTimestamp(instant.getEpochSecond() + SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
/**
* @return the current timestamp in seconds rounded to the closest hour.
* @return the current NTP UTC timestamp in seconds rounded to the closest hour.
*/
public static long hourRoundedCurrentTimeTimestamp() {
return hourRoundedTimestamp(currentNtpTime());
}
/**
* @return the current timestamp in seconds rounded to the closest hour
* @return the current NTP UTC timestamp in seconds rounded to the closest hour
* limited to 32 bits (java int).
*/
public static int hourRoundedCurrentTimeTimestamp32() {
......
package fr.inria.clea.lsp;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import fr.inria.clea.lsp.utils.TimeUtils;
// @ExtendWith(MockitoJUnitRunner.class)
public class LocationTest {
/* Example of a permanent Location Secret Key used for the tests */
private final String permanentLocationSecretKey = "23c9b8f36ac1c0cddaf869c3733b771c3dc409416a9695df40397cea53e7f39e21f76925fc0c74ca6ee7c7eafad92473fd85758bab8f45fe01aac504";
private String[] serverAuthorityKeyPair;
private String[] manualContactTracingAuthorityKeyPair;
private int periodStartTime;
private LocationContact locationContact;
//@Mock
private LocationSpecificPart lsp;
private Location location;
@BeforeEach
public void setUp() throws Exception {
CleaEciesEncoder cleaEciesEncoder = new CleaEciesEncoder();
serverAuthorityKeyPair = cleaEciesEncoder.genKeysPair(true);
manualContactTracingAuthorityKeyPair = cleaEciesEncoder.genKeysPair(true);
periodStartTime = TimeUtils.hourRoundedCurrentTimeTimestamp32();
locationContact = new LocationContact("0612150292", "01234567", periodStartTime);
}
@Test
public void testWhenSettingQrCodeValidityStartTimeWithValidQrCodeRenewalIntervalThenQrValidityStartTimeUpdated() {
int qrCodeRenewalIntervalExponentCompact = 2;
int qrCodeRenewalInterval = 1 << qrCodeRenewalIntervalExponentCompact;
int periodDuration = 3;
lsp = newLocationSpecificPart(qrCodeRenewalIntervalExponentCompact, periodDuration);
location = newLocation(locationContact, lsp);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime);
assertThat(lsp.getQrCodeValidityStartTime()).isEqualTo(periodStartTime);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime + qrCodeRenewalInterval);
assertThat(lsp.getQrCodeValidityStartTime()).isEqualTo(periodStartTime + qrCodeRenewalInterval);
}
@Test
public void testWhenSettingQrCodeValidityStartTimeWithValidQrCodeRenewalIntervalThenQrValidityStartTimeNotUpdated() {
int qrCodeRenewalIntervalExponentCompact = 2;
int periodDuration = 3;
lsp = Mockito.spy(newLocationSpecificPart(qrCodeRenewalIntervalExponentCompact, periodDuration));
location = newLocation(locationContact, lsp);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime - 1);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime + 1);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime + (periodDuration + 1) * 3600);
verify(lsp, never()).setQrCodeValidityStartTime(Mockito.anyInt());
}
@Test
public void testWhenSettingQrCodeValidityStartTimeWithNoQrCodeRenewalIntervalThenQrValidityStartTimeNotUpdated() {
int qrCodeRenewalIntervalExponentCompact = 0x1F;
int periodDuration = 3;
lsp = newLocationSpecificPart(qrCodeRenewalIntervalExponentCompact, periodDuration);
location = newLocation(locationContact, lsp);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime);
assertThat(lsp.getQrCodeValidityStartTime()).isEqualTo(periodStartTime);
location.setQrCodeValidityStartTime(periodStartTime, periodStartTime + 1);
assertThat(lsp.getQrCodeValidityStartTime()).isNotEqualTo(periodStartTime + 1);
}
@Test
public void testNewDeepLink() throws CleaEncryptionException {
int qrCodeRenewalIntervalExponentCompact = 2;
int periodDuration = 3;
lsp = newLocationSpecificPart(qrCodeRenewalIntervalExponentCompact, periodDuration);
location = newLocation(locationContact, lsp);
String deepLink = location.newDeepLink();
assertThat(deepLink).isNotEmpty();
assertThat(deepLink).startsWith(Location.COUNTRY_SPECIFIC_PREFIX);
String deepLink2 = location.newDeepLink(periodStartTime);
assertThat(deepLink2).isNotEmpty();
assertThat(deepLink2).startsWith(Location.COUNTRY_SPECIFIC_PREFIX);
String deepLink3 = location.newDeepLink(periodStartTime, periodStartTime);
assertThat(deepLink3).isNotEmpty();
assertThat(deepLink3).startsWith(Location.COUNTRY_SPECIFIC_PREFIX);
assertThat(deepLink).isNotIn(deepLink2, deepLink3);
assertThat(deepLink2).isNotIn(deepLink, deepLink3);
assertThat(deepLink3).isNotIn(deepLink, deepLink2);
}
protected LocationSpecificPart newLocationSpecificPart(int qrCodeRenewalIntervalExponentCompact,
int periodDuration) {
return LocationSpecificPart.builder().staff(true).countryCode(33)
.qrCodeRenewalIntervalExponentCompact(qrCodeRenewalIntervalExponentCompact).venueType(4)
.venueCategory1(0).venueCategory2(0).periodDuration(periodDuration).build();
}
protected Location newLocation(LocationContact locationContact, LocationSpecificPart lsp) {
return Location.builder().contact(locationContact).locationSpecificPart(lsp)
.manualContactTracingAuthorityPublicKey(manualContactTracingAuthorityKeyPair[1])
.serverAuthorityPublicKey(serverAuthorityKeyPair[1])
.permanentLocationSecretKey(permanentLocationSecretKey).build();
}
}
......@@ -46,5 +46,52 @@ public class TimeUtilsTest {
public void testTimestampIsRoundedUpToTheNextLongWhenModuloIsEqualToHalfTimeRoundingValue() {
assertThat(TimeUtils.hourRoundedTimestamp(1606141800)).isEqualTo(1606143600);
}
@Test
public void testTimestampFromInstantIsRoundedDownWhenModuloLowerThanHalfTimeRoundingValue(){
Instant instant = Instant.parse("1970-01-01T00:10:00.00Z");
assertThat(TimeUtils.hourRoundedTimestampFromInstant(instant)).isEqualTo(TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testTimestampFromInstantIsRoundedUpWhenModuloGreaterThanHalfTimeRoundingValue(){
Instant instant = Instant.parse("1969-12-31T23:50:00.00Z");
assertThat(TimeUtils.hourRoundedTimestampFromInstant(instant)).isEqualTo(TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testTimestampFromInstantIsNotRoundedWhenMultipleOfTimeRoundingValue(){
Instant instant = Instant.parse("1970-01-01T00:00:00.00Z");
assertThat(TimeUtils.hourRoundedTimestampFromInstant(instant)).isEqualTo(TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testTimestampFromInstantIsRoundedUpToTheNextLongWhenModuloIsEqualToHalfTimeRoundingValue(){
Instant instant = Instant.parse("1969-12-31T23:30:00.00Z");
assertThat(TimeUtils.hourRoundedTimestampFromInstant(instant)).isEqualTo(TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testIntTimestampFromInstantIsRoundedDownWhenModuloLowerThanHalfTimeRoundingValue(){
Instant instant = Instant.parse("1970-01-01T00:10:00.00Z");
assertThat(TimeUtils.hourRoundedTimestamp32FromInstant(instant)).isEqualTo((int)TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testIntTimestampFromInstantIsRoundedUpWhenModuloGreaterThanHalfTimeRoundingValue(){
Instant instant = Instant.parse("1969-12-31T23:50:00.00Z");
assertThat(TimeUtils.hourRoundedTimestamp32FromInstant(instant)).isEqualTo((int)TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testIntTimestampFromInstantIsNotRoundedWhenMultipleOfTimeRoundingValue(){
Instant instant = Instant.parse("1970-01-01T00:00:00.00Z");
assertThat(TimeUtils.hourRoundedTimestamp32FromInstant(instant)).isEqualTo((int)TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
@Test
public void testIntTimestampFromInstantIsRoundedUpToTheNextLongWhenModuloIsEqualToHalfTimeRoundingValue(){
Instant instant = Instant.parse("1969-12-31T23:30:00.00Z");
assertThat(TimeUtils.hourRoundedTimestamp32FromInstant(instant)).isEqualTo((int)TimeUtils.SECONDS_FROM_01_01_1900_TO_01_01_1970);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment