From 5e555bb25fafb20017b3ca027610f772e768870f Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 19 May 2021 15:38:58 +0200 Subject: [PATCH] Fixed findTraceKeys dependent on timezone & corresponding unit tests --- .../data/JdbcNotifyMeDataServiceV3Impl.java | 34 ++++++++---- .../backend/data/NotifyMeDataServiceV3.java | 9 +++ .../sdk/backend/model/util/DateUtil.java | 2 +- .../ws/insertmanager/InsertManagerTest.java | 55 ++++++++++--------- .../sdk/backend/ws/util/CryptoUtilV3Test.java | 20 +++---- 5 files changed, 72 insertions(+), 48 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/JdbcNotifyMeDataServiceV3Impl.java b/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/JdbcNotifyMeDataServiceV3Impl.java index 53901d65..edbe21a9 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/JdbcNotifyMeDataServiceV3Impl.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/JdbcNotifyMeDataServiceV3Impl.java @@ -12,11 +12,16 @@ import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey; import ch.ubique.notifyme.sdk.backend.model.util.DateUtil; + +import java.sql.Date; +import java.sql.Timestamp; import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.List; import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; @@ -25,6 +30,8 @@ public class JdbcNotifyMeDataServiceV3Impl implements NotifyMeDataServiceV3 { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + private final Long bucketSizeInMs; private final NamedParameterJdbcTemplate jt; private final SimpleJdbcInsert traceKeyInsert; @@ -46,24 +53,31 @@ public void insertTraceKey(TraceKey traceKey) { @Override @Transactional(readOnly = true) - public List findTraceKeys(Instant after) { + public List findTraceKeys(Instant before, Instant after) { var sql = "select * from t_trace_key_v3"; - final var before = DateUtil.toInstant(DateUtil.getLastFullBucketEndEpochMilli(bucketSizeInMs)); - MapSqlParameterSource params = new MapSqlParameterSource("before", DateUtil.toDate(before)); + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue("before", Timestamp.from(before)); sql += " where created_at < :before"; if (after != null) { sql += " and created_at >= :after"; - params.addValue("after", DateUtil.toDate(after)); +// sql += " where created_at >= :after"; + params.addValue("after", Timestamp.from(after)); } return jt.query(sql, params, new TraceKeyV3RowMapper()); } + @Override + public List findTraceKeys(Instant after) { + final var before = Instant.ofEpochMilli(DateUtil.getLastFullBucketEndEpochMilli(bucketSizeInMs)); + return findTraceKeys(before, after); + } + @Override @Transactional public int removeTraceKeys(Instant before) { final var sql = "delete from t_trace_key_v3 where day < :before"; final var params = new MapSqlParameterSource(); - params.addValue("before", DateUtil.toDate(before)); + params.addValue("before", Timestamp.from(before)); return jt.update(sql, params); } @@ -80,15 +94,15 @@ public void insertTraceKey(List traceKeysToInsert) { } private MapSqlParameterSource getTraceKeyParams(TraceKey traceKey) { - MapSqlParameterSource params = new MapSqlParameterSource(); + var params = new MapSqlParameterSource(); params.addValue("version", traceKey.getVersion()); params.addValue("identity", traceKey.getIdentity()); params.addValue("secret_key_for_identity", traceKey.getSecretKeyForIdentity()); - params.addValue("day", DateUtil.toDate(traceKey.getDay())); + params.addValue("day", Date.from(traceKey.getDay())); if (traceKey.getCreatedAt() != null) { - params.addValue("created_at", DateUtil.toDate(traceKey.getCreatedAt())); + params.addValue("created_at", Timestamp.from(traceKey.getCreatedAt())); } else { - params.addValue("created_at", new Date()); + params.addValue("created_at", Timestamp.from(Instant.now())); } params.addValue("encrypted_associated_data", traceKey.getEncryptedAssociatedData()); params.addValue("cipher_text_nonce", traceKey.getCipherTextNonce()); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/NotifyMeDataServiceV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/NotifyMeDataServiceV3.java index cfe6144c..0f31539c 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/NotifyMeDataServiceV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-data/src/main/java/ch/ubique/notifyme/sdk/backend/data/NotifyMeDataServiceV3.java @@ -28,6 +28,15 @@ public interface NotifyMeDataServiceV3 { * Returns trace keys that where submitted (/created) after the given date. * Returns all trace keys if after == null. * + * @param before + * @param after + * @return + */ + public List findTraceKeys(Instant before, Instant after); + + /** + * Wrapper around findTraceKeys where before is set to the end of the previous bucket + * * @param after * @return */ diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-model/src/main/java/ch/ubique/notifyme/sdk/backend/model/util/DateUtil.java b/notifyme-sdk-backend/notifyme-sdk-backend-model/src/main/java/ch/ubique/notifyme/sdk/backend/model/util/DateUtil.java index feb1c986..b24fcdf2 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-model/src/main/java/ch/ubique/notifyme/sdk/backend/model/util/DateUtil.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-model/src/main/java/ch/ubique/notifyme/sdk/backend/model/util/DateUtil.java @@ -54,7 +54,7 @@ public static boolean isInThePast(Long lastKeyBundleTag) { } public static long getLastFullBucketEndEpochMilli(Long bucketSizeInMs) { - return (System.currentTimeMillis() / bucketSizeInMs) * bucketSizeInMs; + return (Instant.now().toEpochMilli() / bucketSizeInMs) * bucketSizeInMs; } public static String formattedDateTime(final Instant time) { diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java index 80acdc0f..5d34ef4f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java @@ -2,6 +2,7 @@ import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey; import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.FakeRequestFilter; import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.IntervalThresholdFilter; import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.OverlappingIntervalsFilter; @@ -24,6 +25,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import java.util.*; import static org.junit.Assert.*; @@ -51,18 +53,18 @@ public void setUp() throws Exception { @Test @Transactional public void testInsertEmptyList() throws Exception { - final LocalDateTime now = LocalDateTime.now(); + final var now = Instant.now(); assertTrue( - notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); - insertWith(new ArrayList<>(), new ArrayList<>(), now); + notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty()); + insertWith(new ArrayList<>(), new ArrayList<>(), LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId())); assertTrue( - notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty()); } @Test @Transactional public void testInsertInvalidVenueInfo() throws Exception { - final LocalDateTime now = LocalDateTime.now(); + final var now = Instant.now(); UploadInsertionFilter removeAll = new UploadInsertionFilter() { @Override @@ -80,16 +82,16 @@ public List filter( final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( createUploadVenueInfo( - now, now.plusMinutes(60), false)); - insertWith(Collections.singletonList(removeAll), uploadVenueInfoList, now); + now, now.plus(1, ChronoUnit.HOURS), false)); + insertWith(Collections.singletonList(removeAll), uploadVenueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId())); assertTrue( - notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty()); } @Test @Transactional public void testInsertValid() throws Exception { - final LocalDateTime now = LocalDateTime.now(); + final var now = Instant.now(); UploadInsertionFilter removeNone = new UploadInsertionFilter() { @Override @@ -107,29 +109,30 @@ public List filter( final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( createUploadVenueInfo( - now, now.plusMinutes(60), false)); - insertWith(Collections.singletonList(removeNone), uploadVenueInfoList, now); + now.minus(2, ChronoUnit.HOURS), now.minus(1, ChronoUnit.HOURS), false)); + insertWith(Collections.singletonList(removeNone), uploadVenueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId())); + final var traceKeys = notifyMeDataServiceV3.findTraceKeys(now.plus(1, ChronoUnit.HOURS), now.minus(1, ChronoUnit.DAYS)); assertEquals(1, - notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + traceKeys.size()); } @Test @Transactional public void testAddRequestFilters() throws Exception { - final LocalDateTime now = LocalDateTime.now(); + final var now = Instant.now(); final var venueInfoList = new ArrayList(); - final var fakeUpload = createUploadVenueInfo(now.minusDays(6), now.minusDays(5), true); + final var fakeUpload = createUploadVenueInfo(now.minus(6, ChronoUnit.DAYS), now.minus(6, ChronoUnit.DAYS), true); venueInfoList.add(fakeUpload); - final var negativeIntervalUpload = createUploadVenueInfo(now.minusDays(3), now.minusDays(4), false); + final var negativeIntervalUpload = createUploadVenueInfo(now.minus(3, ChronoUnit.DAYS), now.minus(4, ChronoUnit.DAYS), false); venueInfoList.add(negativeIntervalUpload); - final var overlapIntervalUpload1 = createUploadVenueInfo(now.minusHours(60), now.minusDays(2), false); - final var overlapIntervalUpload2 = createUploadVenueInfo(now.minusHours(54), now.minusHours(36), false); + final var overlapIntervalUpload1 = createUploadVenueInfo(now.minus(60, ChronoUnit.HOURS), now.minus(2, ChronoUnit.DAYS), false); + final var overlapIntervalUpload2 = createUploadVenueInfo(now.minus(54, ChronoUnit.HOURS), now.minus(36, ChronoUnit.HOURS), false); venueInfoList.add(overlapIntervalUpload1); venueInfoList.add(overlapIntervalUpload2); - final var validUpload = createUploadVenueInfo(now.minusHours(24), now.minusHours(23), false); + final var validUpload = createUploadVenueInfo(now.minus(24, ChronoUnit.HOURS), now.minus(23, ChronoUnit.HOURS), false); venueInfoList.add(validUpload); - insertWith(Arrays.asList(new FakeRequestFilter(), new IntervalThresholdFilter(), new OverlappingIntervalsFilter()), venueInfoList, now); - assertEquals(1, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + insertWith(Arrays.asList(new FakeRequestFilter(), new IntervalThresholdFilter(), new OverlappingIntervalsFilter()), venueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId())); + assertEquals(1, notifyMeDataServiceV3.findTraceKeys(now.plus(1, ChronoUnit.HOURS), now.minus(1, ChronoUnit.DAYS)).size()); } private void insertWith( @@ -144,16 +147,14 @@ private void insertWith( } } final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var expiry = Instant.now().plus(5, ChronoUnit.MINUTES); final var token = tokenHelper.createToken( "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); insertManager.insertIntoDatabase(uploadVenueInfoList, userAgent, token, now); } - private UploadVenueInfo createUploadVenueInfo(LocalDateTime start, LocalDateTime end, boolean fake) { - final var startInstant = start.toInstant(ZoneOffset.UTC); - final var endInstant = end.toInstant(ZoneOffset.UTC); + private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end, boolean fake) { final var crypto = cryptoWrapper.getCryptoUtilV3(); final var noncesAndNotificationKey = crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); @@ -168,13 +169,13 @@ private UploadVenueInfo createUploadVenueInfo(LocalDateTime start, LocalDateTime crypto.concatenate( "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), crypto.longToBytes(3600L), - crypto.longToBytes(startInstant.getEpochSecond()), + crypto.longToBytes(start.getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); return UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) - .setIntervalStartMs(startInstant.toEpochMilli()) - .setIntervalEndMs(endInstant.toEpochMilli()) + .setIntervalStartMs(start.toEpochMilli()) + .setIntervalEndMs(end.toEpochMilli()) .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) .setFake(fake) .build(); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3Test.java index ee067bd7..3ddc31f9 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3Test.java @@ -1,22 +1,19 @@ package ch.ubique.notifyme.sdk.backend.ws.util; +import static org.junit.Assert.*; + import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; -import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey; import com.google.gson.Gson; import com.google.protobuf.ByteString; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CryptoUtilV3Test { @@ -69,7 +66,10 @@ public void testCreateTraceV3ForUserUpload() { .setVersion(3) .addVenueInfos(uploadVenueInfo) .build(); - final var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUpload); + final var traceKeys = + cryptoWrapper + .getCryptoUtilV3() + .createTraceV3ForUserUpload(userUpload.getVenueInfosList()); assertNotNull(traceKeys); assertEquals(1, traceKeys.size()); }