From dca11206854804df9c4a84d092f358d70b5c6738 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 11 May 2021 13:39:12 +0200 Subject: [PATCH 01/19] Implemented InsertManager We can now apply arbitrary filters to a given list of UploadVenueInfo objects. All objects that aren't removed from the list by one of the filters are transformed into TraceKeys and inserted into the database. The InsertManager's main use will be validating /userupload requests --- .../sdk/backend/ws/config/WSBaseConfig.java | 11 +++ .../ws/controller/NotifyMeControllerV3.java | 34 +++++-- .../ws/insert_manager/InsertException.java | 5 + .../ws/insert_manager/InsertManager.java | 98 +++++++++++++++++++ .../sdk/backend/ws/insert_manager/OSType.java | 18 ++++ .../UploadInsertionFilter.java | 42 ++++++++ .../security/NotifyMeJwtRequestValidator.java | 15 ++- .../sdk/backend/ws/util/CryptoUtilV3.java | 4 +- .../controller/NotifyMeControllerV3Test.java | 12 ++- .../backend/ws/crypto/SodiumWrapperTest.java | 2 +- .../swagger/swagger.yaml | 9 ++ 11 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java index a31ddca7..9e0f2b71 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java @@ -25,6 +25,7 @@ import ch.ubique.notifyme.sdk.backend.ws.controller.NotifyMeControllerV3; import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebController; import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebCriticalEventController; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtRequestValidator; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator; import ch.ubique.notifyme.sdk.backend.ws.service.PhoneHeartbeatSilentPush; @@ -168,6 +169,14 @@ public UUIDDataService uuidDataService() { return new UUIDDataServiceImpl(dataSource()); } + @Bean + public InsertManager insertManager( + final CryptoWrapper cryptoWrapper, + final NotifyMeDataServiceV3 notifyMeDataServiceV3 + ) { + return new InsertManager(cryptoWrapper, notifyMeDataServiceV3); + } + @Bean public NotifyMeControllerV2 notifyMeControllerV2( final NotifyMeDataServiceV2 notifyMeDataService, @@ -184,6 +193,7 @@ public NotifyMeControllerV2 notifyMeControllerV2( @Bean public NotifyMeControllerV3 notifyMeControllerV3( NotifyMeDataServiceV3 notifyMeDataServiceV3, + InsertManager insertManager, PushRegistrationDataService pushRegistrationDataService, UUIDDataService uuidDataService, RequestValidator requestValidator, @@ -191,6 +201,7 @@ public NotifyMeControllerV3 notifyMeControllerV3( String revision) { return new NotifyMeControllerV3( notifyMeDataServiceV3, + insertManager, pushRegistrationDataService, uuidDataService, requestValidator, diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java index 57fe1b7a..1b1cb263 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java @@ -20,6 +20,8 @@ import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEvent; import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEvent.Builder; import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEventWrapper; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator.NotAJwtException; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator.WrongAudienceException; @@ -30,6 +32,7 @@ import com.google.protobuf.ByteString; import java.io.UnsupportedEncodingException; import java.time.Duration; +import java.time.Instant; import java.time.LocalDateTime; import java.util.List; import java.util.concurrent.Callable; @@ -42,13 +45,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.*; @Controller @RequestMapping("/v3") @@ -58,6 +55,7 @@ public class NotifyMeControllerV3 { private static final Logger logger = LoggerFactory.getLogger(NotifyMeControllerV3.class); private final NotifyMeDataServiceV3 dataService; + private final InsertManager insertManager; private final PushRegistrationDataService pushRegistrationDataService; private final UUIDDataService uuidDataService; private final RequestValidator requestValidator; @@ -70,6 +68,7 @@ public class NotifyMeControllerV3 { public NotifyMeControllerV3( NotifyMeDataServiceV3 dataService, + InsertManager insertManager, PushRegistrationDataService pushRegistrationDataService, UUIDDataService uuidDataService, RequestValidator requestValidator, @@ -79,6 +78,7 @@ public NotifyMeControllerV3( Long traceKeysCacheControlInMs, Duration requestTime) { this.dataService = dataService; + this.insertManager = insertManager; this.pushRegistrationDataService = pushRegistrationDataService; this.uuidDataService = uuidDataService; this.requestValidator = requestValidator; @@ -230,6 +230,13 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { public @ResponseBody Callable> userUpload( @Documentation(description = "Identities to upload as protobuf") @Valid @RequestBody final UserUploadPayload userUploadPayload, + @RequestHeader(value = "User-Agent") + @Documentation( + description = + "App Identifier (PackageName/BundleIdentifier) + App-Version +" + + " OS (Android/iOS) + OS-Version", + example = "ch.ubique.android.dp3t;1.0;iOS;13.3") + String userAgent, @AuthenticationPrincipal @Documentation(description = "JWT token that can be verified by the backend server") Object principal) @@ -237,10 +244,17 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { UnsupportedEncodingException { final var now = LocalDateTime.now(); - // requestValidator.isValid(principal); + try { + insertManager.insertIntoDatabase( + userUploadPayload.getVenueInfosList(), userAgent, principal, now); + } catch (InsertException e) { + // TODO What to do + } + +// requestValidator.isValid(principal); - var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUploadPayload); - dataService.insertTraceKey(traceKeys); +// var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUploadPayload.getVenueInfosList()); +// dataService.insertTraceKey(traceKeys); return () -> { try { diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java new file mode 100644 index 00000000..abd10811 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java @@ -0,0 +1,5 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager; + +public abstract class InsertException extends Exception { + private static final long serialVersionUID = 6476089262577182680L; +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java new file mode 100644 index 00000000..3c0119aa --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java @@ -0,0 +1,98 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager; + +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.insert_manager.insertion_filters.UploadInsertionFilter; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; +import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class InsertManager { + + private static final Logger logger = LoggerFactory.getLogger(InsertManager.class); + + private final List filterList = new ArrayList<>(); + + private final CryptoWrapper cryptoWrapper; + private final NotifyMeDataServiceV3 notifyMeDataServiceV3; + + public InsertManager(CryptoWrapper cryptoWrapper, NotifyMeDataServiceV3 notifyMeDataServiceV3) { + this.cryptoWrapper = cryptoWrapper; + this.notifyMeDataServiceV3 = notifyMeDataServiceV3; + } + + public void addFilter(UploadInsertionFilter filter) { + this.filterList.add(filter); + } + + public void insertIntoDatabase( + List uploadVenueInfoList, + String header, + Object principal, + LocalDateTime now + ) throws InsertException { + if (uploadVenueInfoList != null && !uploadVenueInfoList.isEmpty()) { + final var traceKeys = filterUpload(uploadVenueInfoList, header, principal, now); + if (!traceKeys.isEmpty()) { + notifyMeDataServiceV3.insertTraceKey(traceKeys); + } + } + } + + private List filterUpload(List uploadVenueInfoList, String header, Object principal, LocalDateTime now) throws InsertException { + var headerParts = header.split(";"); + if (headerParts.length < 5) { + headerParts = + List.of("org.example.dp3t", "1.0.0", "0", "Android", "29").toArray(new String[0]); + logger.error("We received an invalid header, setting default."); + } + + // Map the given headers to os type, os version and app version. Examples are: + // ch.admin.bag.dp36;1.0.7;200724.1105.215;iOS;13.6 + // ch.admin.bag.dp3t.dev;1.0.7;1595591959493;Android;29 + var osType = exctractOS(headerParts[3]); + var osVersion = extractOsVersion(headerParts[4]); + var appVersion = extractAppVersion(headerParts[1], headerParts[2]); + + var venueInfoList = uploadVenueInfoList; + for (UploadInsertionFilter insertionFilter: filterList) { + venueInfoList = insertionFilter.filter(now, venueInfoList, osType, osVersion, appVersion, principal); + } + return cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(venueInfoList); + } + + /** + * Extracts the {@link OSType} from the osString that is given by the client request. + * + * @param osString + * @return + */ + private OSType exctractOS(String osString) { + var result = OSType.ANDROID; + switch (osString.toLowerCase()) { + case "ios": + result = OSType.IOS; + break; + case "android": + break; + default: + result = OSType.ANDROID; + } + return result; + } + + private Version extractOsVersion(String osVersionString) { + return new Version(osVersionString); + } + + private Version extractAppVersion(String osAppVersionString, String osMetaInfo) { + return new Version(osAppVersionString + "+" + osMetaInfo); + } + +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java new file mode 100644 index 00000000..c70579da --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java @@ -0,0 +1,18 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager; + +public enum OSType { + ANDROID, + IOS; + + @Override + public String toString() { + switch (this) { + case ANDROID: + return "Android"; + case IOS: + return "iOS"; + default: + return "Unknown"; + } + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java new file mode 100644 index 00000000..bdf57c34 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java @@ -0,0 +1,42 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +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.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.List; + +/** + * Interface for filters that can be configured in the {@link InsertManager} + */ +public interface UploadInsertionFilter { + + /** + * The {@link InsertManager} goes through all configured filters and calls the with a list of + * {@link UploadVenueInfo}. The filters are applied before transforming the {@param + * uploadVenueInfoList} into a {@link TraceKey} list to be inserted into the database. + * + * @param now current timestamp + * @param uploadVenueInfoList the list of venue info objects to be inserted + * @param osType the os type of the client + * @param osVersion the os version of the client + * @param appVersion the app version of the client + * @param principal the authorization context which belongs to the uploaded keys. This will + * usually be a JWT token. + * @return Filtered list of {@link UploadVenueInfo} elements + * @throws InsertException + */ + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException; +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java index 4420df83..c96bc1e6 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java @@ -1,7 +1,10 @@ package ch.ubique.notifyme.sdk.backend.ws.security; +import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey; import org.springframework.security.oauth2.jwt.Jwt; +import java.time.format.DateTimeFormatter; + public class NotifyMeJwtRequestValidator implements RequestValidator { @Override @@ -23,8 +26,16 @@ public boolean isValid(Object authObject) throws WrongScopeException, WrongAudie @Override public long validateKeyDate(Object authObject, Object others) throws ClaimIsBeforeOnsetException, InvalidDateException { - // TODO Implement - return 0; + // TODO Implement: Check not larger than threshold (~24h), onset before start of interval (for each interval) + final var DATE_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd"); // parse as local date + if (authObject instanceof Jwt) { + Jwt token = (Jwt) authObject; +// var jwtKeyDate = DateTime.parseDate(token.getClaim("onset")); + if(others instanceof TraceKey) { + final var key = (TraceKey) others; + } + } + throw new IllegalArgumentException(); } @Override diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3.java index 2fa908db..d830d310 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/util/CryptoUtilV3.java @@ -82,9 +82,9 @@ public void testFlow() { } public List - createTraceV3ForUserUpload(UserUploadPayloadOuterClass.UserUploadPayload userUpload) { + createTraceV3ForUserUpload(List uploadVenueInfoList) { var traceKeys = new ArrayList(); - for (UserUploadPayloadOuterClass.UploadVenueInfo venueInfo : userUpload.getVenueInfosList()) { + for (UserUploadPayloadOuterClass.UploadVenueInfo venueInfo : uploadVenueInfoList) { if (!venueInfo.getFake()) { byte[] identity = cryptoHashSHA256( diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index 928e505a..f480be02 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -154,6 +154,7 @@ public void testUploadAndGetTraceKeys() throws Exception { tokenHelper.createToken( "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); final var mvcResult = mockMvc @@ -161,11 +162,11 @@ public void testUploadAndGetTraceKeys() throws Exception { post("/v3/userupload") .contentType("application/x-protobuf") .header("Authorization", "Bearer " + token) + .header("User-Agent", userAgent) .content(payloadBytes)) .andExpect(request().asyncStarted()) .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); - final MockHttpServletResponse response = mockMvc .perform(get("/v3/traceKeys").accept("application/protobuf")) @@ -196,7 +197,7 @@ public void testUserUploadDuration() throws Exception { final var token = tokenHelper.createToken( "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); - + final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); final var mvcResult = mockMvc @@ -204,6 +205,7 @@ public void testUserUploadDuration() throws Exception { post("/v3/userupload") .contentType("application/x-protobuf") .header("Authorization", "Bearer " + token) + .header("User-Agent", userAgent) .content(payloadBytes)) .andExpect(request().asyncStarted()) .andReturn(); @@ -222,13 +224,14 @@ public void testUserUploadValidToken() throws Exception { final var token = tokenHelper.createToken( "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); - + final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var mvcResult = mockMvc .perform( post("/v3/userupload") .contentType("application/x-protobuf") .header("Authorization", "Bearer " + token) + .header("User-Agent", userAgent) .content(payloadBytes)) .andExpect(request().asyncStarted()) .andReturn(); @@ -244,13 +247,14 @@ public void testUserUploadInvalidToken() throws Exception { final var token = tokenHelper.createToken( "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false); - + final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var result = mockMvc .perform( post("/v3/userupload") .contentType("application/x-protobuf") .header("Authorization", "Bearer " + token) + .header("User-Agent", userAgent) .content(payloadBytes)) .andExpect(request().asyncNotStarted()) .andExpect(status().is(401)) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/crypto/SodiumWrapperTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/crypto/SodiumWrapperTest.java index d27850e0..02f2cacb 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/crypto/SodiumWrapperTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/crypto/SodiumWrapperTest.java @@ -171,7 +171,7 @@ public void testUserUpload() UserUploadPayload userUpload = userUploadBuilder.build(); List traceKeys = - cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUpload); + cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUpload.getVenueInfosList()); // 1 hour checkin, should give 2 matches, as long es the test does not run // exactly at the full hour. diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml b/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml index 174c41fd..61333ac1 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml @@ -240,6 +240,15 @@ paths: schema: $ref: '#/components/schemas/ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UserUploadPayload' description: Identities to upload as protobuf + parameters: + - name: User-Agent + in: header + description: App Identifier (PackageName/BundleIdentifier) + App-Version + + OS (Android/iOS) + OS-Version + example: ch.ubique.android.dp3t;1.0;iOS;13.3 + required: true + schema: + type: string components: schemas: ch.ubique.notifyme.sdk.backend.model.ProblematicEventWrapperOuterClass.ProblematicEvent: From 62e1b6cddfc500b7559e0aea24d79caf0e02369f Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 11 May 2021 15:41:03 +0200 Subject: [PATCH 02/19] Implemented basic insertManager tests --- .../sdk/backend/ws/config/TestConfig.java | 5 +- .../ws/insert_manager/InsertManagerTest.java | 156 ++++++++++++++++++ .../TestInsertManagerApplication.java | 6 + 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/TestConfig.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/TestConfig.java index 008bc6a7..26d51597 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/TestConfig.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/TestConfig.java @@ -14,10 +14,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; -@Configuration("test-config") + +@Profile("test-config") +@Configuration public class TestConfig { @Autowired DataSource dataSource; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java new file mode 100644 index 00000000..8e2f3d87 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java @@ -0,0 +1,156 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager; + +import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import ch.ubique.notifyme.sdk.backend.ws.config.WSDevConfig; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.UploadInsertionFilter; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; +import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; +import ch.ubique.notifyme.sdk.backend.ws.util.TokenHelper; +import com.google.protobuf.ByteString; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.TransactionManager; +import org.springframework.transaction.annotation.Transactional; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ActiveProfiles({"dev", "test-config"}) +public class InsertManagerTest { + + InsertManager insertManager; + + @Autowired NotifyMeDataServiceV3 notifyMeDataServiceV3; + @Autowired CryptoWrapper cryptoWrapper; + + @Autowired + TransactionManager transactionManager; + + private TokenHelper tokenHelper; + + @Before + public void setUp() throws Exception { + tokenHelper = new TokenHelper(); + insertManager = new InsertManager(cryptoWrapper, notifyMeDataServiceV3); + } + + @Test + @Transactional + public void testInsertEmptyList() throws Exception { + final LocalDateTime now = LocalDateTime.now(); + assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + insertWith(null, new ArrayList<>(), now); + assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + } + + @Test + @Transactional + public void testInsertInvalidVenueInfo() throws Exception { + final LocalDateTime now = LocalDateTime.now(); + UploadInsertionFilter removeAll = + new UploadInsertionFilter() { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + return new ArrayList<>(); + } + }; + final List uploadVenueInfoList = new ArrayList<>(); + uploadVenueInfoList.add( + createUploadVenueInfo( + now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); + insertWith(removeAll, uploadVenueInfoList, now); + assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + } + + @Test + @Transactional + public void testInsertInvalidUserAgent() throws Exception { + // TODO: Add filter that removes any upload + } + + @Test + @Transactional + public void testInsertValid() throws Exception { + final LocalDateTime now = LocalDateTime.now(); + UploadInsertionFilter removeNone = + new UploadInsertionFilter() { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + return uploadVenueInfoList; + } + }; + final List uploadVenueInfoList = new ArrayList<>(); + uploadVenueInfoList.add( + createUploadVenueInfo( + now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); + insertWith(removeNone, uploadVenueInfoList, now); + assertFalse(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + } + + private void insertWith(UploadInsertionFilter insertionFilter, List uploadVenueInfoList, LocalDateTime now) throws Exception { + if (insertionFilter != null) { + insertManager.addFilter(insertionFilter); + } + 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 token = + tokenHelper.createToken( + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + insertManager.insertIntoDatabase(uploadVenueInfoList, userAgent, token, now); + } + + private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end) { + final var crypto = cryptoWrapper.getCryptoUtilV3(); + final var noncesAndNotificationKey = + crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); + byte[] preid = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-PREID".getBytes(StandardCharsets.US_ASCII), + "payload".getBytes(StandardCharsets.US_ASCII), + noncesAndNotificationKey.noncePreId)); + byte[] timekey = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), + crypto.longToBytes(3600L), + crypto.longToBytes(start.getEpochSecond()), + noncesAndNotificationKey.nonceTimekey)); + return UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(start.getEpochSecond()) + .setIntervalEndMs(end.getEpochSecond()) + .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) + .build(); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java new file mode 100644 index 00000000..f346dae7 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java @@ -0,0 +1,6 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = {"ch.ubique.notifyme.sdk.backend.ws.config"}) +public class TestInsertManagerApplication {} \ No newline at end of file From 4661fabf2310bcb74c04c3840da2d9a83dca3095 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 11 May 2021 16:18:47 +0200 Subject: [PATCH 03/19] Cleaned up test application context --- ...rApplication.java => TestApplication.java} | 4 +- .../backend/ws/config/JWTValidationTest.java | 6 +-- .../ws/insert_manager/InsertManagerTest.java | 40 ++++++++++--------- .../TestInsertManagerApplication.java | 6 --- 4 files changed, 25 insertions(+), 31 deletions(-) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{controller/TestControllerApplication.java => TestApplication.java} (83%) delete mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/TestControllerApplication.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/TestApplication.java similarity index 83% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/TestControllerApplication.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/TestApplication.java index 7d01fcb2..f69b8553 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/TestControllerApplication.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/TestApplication.java @@ -8,9 +8,9 @@ * SPDX-License-Identifier: MPL-2.0 */ -package ch.ubique.notifyme.sdk.backend.ws.controller; +package ch.ubique.notifyme.sdk.backend.ws; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(scanBasePackages = {"ch.ubique.notifyme.sdk.backend.ws.config"}) -public class TestControllerApplication {} +public class TestApplication {} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java index e0b78728..f863d90f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java @@ -25,21 +25,19 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest(classes = WSDevConfig.class) +@SpringBootTest @ActiveProfiles({"dev", "jwt"}) @TestPropertySource(properties = {"ws.app.jwt.publickey=classpath://generated_public_test.pem"}) public class JWTValidationTest { @Autowired UUIDDataService uuidDataService; - // TODO: How to do this nicely with dependency injection? - JwtDecoder jwtDecoder; + @Autowired JwtDecoder jwtDecoder; TokenHelper tokenHelper; @Before public void setup() throws Exception { tokenHelper = new TokenHelper(); - jwtDecoder = jwtDecoder(); } @Test diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java index 8e2f3d87..9c79608d 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java @@ -2,7 +2,6 @@ import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; -import ch.ubique.notifyme.sdk.backend.ws.config.WSDevConfig; import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.UploadInsertionFilter; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; @@ -26,7 +25,8 @@ import java.util.Date; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) @SpringBootTest @@ -38,8 +38,7 @@ public class InsertManagerTest { @Autowired NotifyMeDataServiceV3 notifyMeDataServiceV3; @Autowired CryptoWrapper cryptoWrapper; - @Autowired - TransactionManager transactionManager; + @Autowired TransactionManager transactionManager; private TokenHelper tokenHelper; @@ -53,9 +52,11 @@ public void setUp() throws Exception { @Transactional public void testInsertEmptyList() throws Exception { final LocalDateTime now = LocalDateTime.now(); - assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + assertTrue( + notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); insertWith(null, new ArrayList<>(), now); - assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + assertTrue( + notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); } @Test @@ -78,16 +79,11 @@ public List filter( }; final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( - createUploadVenueInfo( - now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); + createUploadVenueInfo( + now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); insertWith(removeAll, uploadVenueInfoList, now); - assertTrue(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); - } - - @Test - @Transactional - public void testInsertInvalidUserAgent() throws Exception { - // TODO: Add filter that removes any upload + assertTrue( + notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); } @Test @@ -110,13 +106,18 @@ public List filter( }; final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( - createUploadVenueInfo( - now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); + createUploadVenueInfo( + now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); insertWith(removeNone, uploadVenueInfoList, now); - assertFalse(notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + assertFalse( + notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); } - private void insertWith(UploadInsertionFilter insertionFilter, List uploadVenueInfoList, LocalDateTime now) throws Exception { + private void insertWith( + UploadInsertionFilter insertionFilter, + List uploadVenueInfoList, + LocalDateTime now) + throws Exception { if (insertionFilter != null) { insertManager.addFilter(insertionFilter); } @@ -151,6 +152,7 @@ private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end) { .setIntervalStartMs(start.getEpochSecond()) .setIntervalEndMs(end.getEpochSecond()) .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) + .setFake(false) .build(); } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java deleted file mode 100644 index f346dae7..00000000 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/TestInsertManagerApplication.java +++ /dev/null @@ -1,6 +0,0 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager; - -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication(scanBasePackages = {"ch.ubique.notifyme.sdk.backend.ws.config"}) -public class TestInsertManagerApplication {} \ No newline at end of file From 3b3c17b59943b56d9fc71b51cfb8bd547b41e110 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 11 May 2021 16:19:32 +0200 Subject: [PATCH 04/19] Implemented fake request filter & tests --- .../insertion_filters/FakeRequestFilter.java | 30 ++++++++ .../FakeRequestFilterTest.java | 57 +++++++++++++++ .../UploadInsertionFilterTest.java | 70 +++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java new file mode 100644 index 00000000..f1ef9a7c --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java @@ -0,0 +1,30 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + * To prevent the possibility of traffic analysis, fake requests are sent at semi-regular intervals. + * Fake uploads don't actually need to be inserted into the database and can therefore be dropped. + */ +public class FakeRequestFilter implements UploadInsertionFilter { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + return uploadVenueInfoList.stream() + .filter(uploadVenueInfo -> !uploadVenueInfo.getFake()) + .collect(Collectors.toList()); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java new file mode 100644 index 00000000..8f3168ab --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java @@ -0,0 +1,57 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import com.google.protobuf.ByteString; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +public class FakeRequestFilterTest extends UploadInsertionFilterTest { + @Override + UploadVenueInfo getValidVenueInfo() { + final UploadVenueInfo.Builder builder = getBuilder(); + return builder.setFake(false).build(); + } + + @Override + UploadVenueInfo getInvalidVenueInfo() { + final UploadVenueInfo.Builder builder = getBuilder(); + return builder.setFake(true).build(); + } + + @Override + UploadInsertionFilter insertionFilter() { + return new FakeRequestFilter(); + } + + private UploadVenueInfo.Builder getBuilder() { + LocalDateTime start = LocalDateTime.now(); + LocalDateTime end = start.plusMinutes(30); + final var crypto = cryptoWrapper.getCryptoUtilV3(); + final var noncesAndNotificationKey = + crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); + byte[] preid = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-PREID".getBytes(StandardCharsets.US_ASCII), + "payload".getBytes(StandardCharsets.US_ASCII), + noncesAndNotificationKey.noncePreId)); + byte[] timekey = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), + crypto.longToBytes(3600L), + crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), + noncesAndNotificationKey.nonceTimekey)); + final var builder = + UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).getEpochSecond()) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).getEpochSecond()) + .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)); + return builder; + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java new file mode 100644 index 00000000..5bc3cee0 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java @@ -0,0 +1,70 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; +import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; +import ch.ubique.notifyme.sdk.backend.ws.util.TokenHelper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ActiveProfiles({"dev", "test-config"}) +public abstract class UploadInsertionFilterTest { + @Autowired CryptoWrapper cryptoWrapper; + private TokenHelper tokenHelper; + + abstract UploadVenueInfo getValidVenueInfo(); + abstract UploadVenueInfo getInvalidVenueInfo(); + abstract UploadInsertionFilter insertionFilter(); + + @Before + public void setUp() throws Exception { + tokenHelper = new TokenHelper(); + } + + @Test + public void testFilterValid() throws Exception { + LocalDateTime now = LocalDateTime.now(); + final List uploadVenueInfoList = new ArrayList<>(); + uploadVenueInfoList.add(getValidVenueInfo()); + final var osType = OSType.ANDROID; + final var osVersion = new Version("29"); + final var appVersion = new Version("1.0.0+0"); + final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var token = + tokenHelper.createToken( + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + assertFalse(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); + } + + @Test + public void testFilterInvalid() throws Exception { + LocalDateTime now = LocalDateTime.now(); + final List uploadVenueInfoList = new ArrayList<>(); + uploadVenueInfoList.add(getInvalidVenueInfo()); + final var osType = OSType.ANDROID; + final var osVersion = new Version("29"); + final var appVersion = new Version("1.0.0+0"); + final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var token = + tokenHelper.createToken( + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + assertTrue(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); + } +} From 001bc48eff56d88079ed8cf9f271ed251bca7eb6 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 08:50:09 +0200 Subject: [PATCH 05/19] Implemented IntervalThresholdFilter: Filters an uploadVenueInfo object when endTime - startTime is outside of ]0,24] (in hours) --- .../IntervalThresholdFilter.java | 34 +++++++++++ .../IntervalThresholdFilterTest.java | 57 +++++++++++++++++++ .../UploadInsertionFilterTest.java | 22 ++++--- 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java new file mode 100644 index 00000000..805ee0ac --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java @@ -0,0 +1,34 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + * TODO: What's the minimum value we can use here? + * The app doesn't support store visit of longer than 24 hours (users are automatically checked out). + * UploadVenueInfo objects that break the interval threshold of (0,24) are dropped. + */ +public class IntervalThresholdFilter implements UploadInsertionFilter { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + return uploadVenueInfoList.stream().filter(uploadVenueInfo -> { + final var start = uploadVenueInfo.getIntervalStartMs(); + final var end = uploadVenueInfo.getIntervalEndMs(); + return (end - start > 0 && end - start <= 24 * 60 * 60 * 1000); + }).collect(Collectors.toList()); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java new file mode 100644 index 00000000..15bf35e7 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java @@ -0,0 +1,57 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import com.google.protobuf.ByteString; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +public class IntervalThresholdFilterTest extends UploadInsertionFilterTest { + @Override + UserUploadPayloadOuterClass.UploadVenueInfo getValidVenueInfo() { + LocalDateTime start = LocalDateTime.now(); + LocalDateTime end = start.plusHours(2); + return getVenueInfo(start, end); + } + + @Override + UserUploadPayloadOuterClass.UploadVenueInfo getInvalidVenueInfo() { + LocalDateTime start = LocalDateTime.now(); + LocalDateTime end = start.plusHours(-1); + return getVenueInfo(start, end); + } + + @Override + UploadInsertionFilter insertionFilter() { + return new IntervalThresholdFilter(); + } + + private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( + LocalDateTime start, LocalDateTime end) { + final var crypto = cryptoWrapper.getCryptoUtilV3(); + final var noncesAndNotificationKey = + crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); + byte[] preid = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-PREID".getBytes(StandardCharsets.US_ASCII), + "payload".getBytes(StandardCharsets.US_ASCII), + noncesAndNotificationKey.noncePreId)); + byte[] timekey = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), + crypto.longToBytes(3600L), + crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), + noncesAndNotificationKey.nonceTimekey)); + return UserUploadPayloadOuterClass.UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).getEpochSecond()) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).getEpochSecond()) + .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) + .setFake(false) + .build(); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java index 5bc3cee0..8d6bbeb0 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java @@ -15,6 +15,9 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -29,10 +32,19 @@ public abstract class UploadInsertionFilterTest { @Autowired CryptoWrapper cryptoWrapper; private TokenHelper tokenHelper; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd"); + abstract UploadVenueInfo getValidVenueInfo(); abstract UploadVenueInfo getInvalidVenueInfo(); abstract UploadInsertionFilter insertionFilter(); + public String getToken(LocalDateTime now) throws Exception { + final var onset = now.minusDays(5).truncatedTo(ChronoUnit.DAYS).format(DATE_FORMATTER); + final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); + return tokenHelper.createToken( + onset, "0", "notifyMe", "userupload", Date.from(expiry), true); + } + @Before public void setUp() throws Exception { tokenHelper = new TokenHelper(); @@ -46,10 +58,7 @@ public void testFilterValid() throws Exception { final var osType = OSType.ANDROID; final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); - final var token = - tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + final var token = getToken(now); assertFalse(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); } @@ -61,10 +70,7 @@ public void testFilterInvalid() throws Exception { final var osType = OSType.ANDROID; final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); - final var token = - tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + final var token = getToken(now); assertTrue(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); } } From 8af0c39715de48065655dbde5fd492711e5ca09a Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 10:34:52 +0200 Subject: [PATCH 06/19] Implemented BeforeOnsetFilter: UploadVenueInfo objects whose endTimeStamp is (strictly) before the onset date are now dropped. --- .../insertion_filters/BeforeOnsetFilter.java | 39 ++++++++++ .../security/NotifyMeJwtRequestValidator.java | 23 +++--- .../backend/ws/security/RequestValidator.java | 13 ++-- .../backend/ws/config/JWTValidationTest.java | 14 ---- .../BeforeOnsetFilterTest.java | 76 +++++++++++++++++++ .../IntervalThresholdFilterTest.java | 1 + .../UploadInsertionFilterTest.java | 31 +++++--- 7 files changed, 154 insertions(+), 43 deletions(-) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java new file mode 100644 index 00000000..ffacca6f --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java @@ -0,0 +1,39 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtRequestValidator; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +/** + * When a person tests positive, the "onset" date since when they are infectious is estimated. + * Visits which occurred before the onset are dropped. + */ +public class BeforeOnsetFilter implements UploadInsertionFilter { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + final var notifyMeJwtRequestValidator = new NotifyMeJwtRequestValidator(); + return uploadVenueInfoList.stream() + .filter( + uploadVenueInfo -> { + final var epochMilli = Instant.ofEpochMilli(uploadVenueInfo.getIntervalEndMs()); + return notifyMeJwtRequestValidator.isOnsetBefore( + principal, LocalDateTime.ofInstant(epochMilli, ZoneOffset.UTC)); + }) + .collect(Collectors.toList()); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java index c96bc1e6..4e7224a0 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java @@ -1,8 +1,9 @@ package ch.ubique.notifyme.sdk.backend.ws.security; -import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey; import org.springframework.security.oauth2.jwt.Jwt; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class NotifyMeJwtRequestValidator implements RequestValidator { @@ -25,19 +26,17 @@ public boolean isValid(Object authObject) throws WrongScopeException, WrongAudie } @Override - public long validateKeyDate(Object authObject, Object others) throws ClaimIsBeforeOnsetException, InvalidDateException { - // TODO Implement: Check not larger than threshold (~24h), onset before start of interval (for each interval) - final var DATE_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd"); // parse as local date - if (authObject instanceof Jwt) { - Jwt token = (Jwt) authObject; -// var jwtKeyDate = DateTime.parseDate(token.getClaim("onset")); - if(others instanceof TraceKey) { - final var key = (TraceKey) others; - } - } - throw new IllegalArgumentException(); + public boolean isOnsetBefore(Object authObject, LocalDateTime dateTime) { + if(authObject instanceof Jwt) { + Jwt token = (Jwt) authObject; + final var dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + final var onset = LocalDate.parse(token.getClaim("onset"), dateTimeFormatter); + return !onset.isAfter(dateTime.toLocalDate()); // Use isAfter because onset could be on the same day + } + return false; } + @Override public boolean isFakeRequest(Object authObject, Object others) { // TODO Implement diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/RequestValidator.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/RequestValidator.java index 6cc8faba..b6a86c02 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/RequestValidator.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/RequestValidator.java @@ -1,5 +1,7 @@ package ch.ubique.notifyme.sdk.backend.ws.security; +import java.time.LocalDateTime; + public interface RequestValidator { /** * Checks if the authObject contains the correct scope and audience @@ -10,16 +12,13 @@ public boolean isValid(Object authObject) throws WrongScopeException, WrongAudienceException, NotAJwtException; /** - * Checks if the date in the onset claim is before the request's issue date + * Checks if the date in the onset claim is before the given date * * @param authObject JWT containing the onset claim - * @param others Key containing the issue date - * @return onset date if successful - * @throws ClaimIsBeforeOnsetException - * @throws InvalidDateException + * @param dateTime Date to check + * @return true if onset is before dateTime, false otherwise */ - public long validateKeyDate(Object authObject, Object others) - throws ClaimIsBeforeOnsetException, InvalidDateException; + public boolean isOnsetBefore(Object authObject, LocalDateTime dateTime); /** * Checks if the request is fake by checking both the token's fake claim and the request's "fake" diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java index f863d90f..3339bb7e 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java @@ -59,18 +59,4 @@ public void testDecoderInvalid() throws Exception { "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false); assertThrows(JwtException.class, () -> jwtDecoder.decode(accessToken)); } - - private NotifyMeJwtValidator jwtValidator() { - return new NotifyMeJwtValidator(uuidDataService, Duration.ofMinutes(60)); - } - - private JwtDecoder jwtDecoder() - throws IOException, KeyVault.PublicKeyNoSuitableEncodingFoundException { - final var nimbusJwtDecoder = - NimbusJwtDecoder.withPublicKey(tokenHelper.getPublicKey()) - .signatureAlgorithm(SignatureAlgorithm.RS256) - .build(); - nimbusJwtDecoder.setJwtValidator(jwtValidator()); - return nimbusJwtDecoder; - } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java new file mode 100644 index 00000000..a52cbd44 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java @@ -0,0 +1,76 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import com.google.protobuf.ByteString; +import org.springframework.security.oauth2.jwt.Jwt; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.Date; + +public class BeforeOnsetFilterTest extends UploadInsertionFilterTest { + + // We don't care about the current time in the filter, we just need a common timestamp for all methods below + private static final LocalDateTime currentTime = LocalDateTime.now(); + + + @Override + UserUploadPayloadOuterClass.UploadVenueInfo getValidVenueInfo() { + LocalDateTime start = currentTime.minusDays(1); + LocalDateTime end = start.plusHours(1); + return getVenueInfo(start, end); + } + + @Override + UserUploadPayloadOuterClass.UploadVenueInfo getInvalidVenueInfo() { + LocalDateTime start = currentTime.minusDays(3); + LocalDateTime end = start.plusHours(1); + return getVenueInfo(start, end); + } + + @Override + UploadInsertionFilter insertionFilter() { + return new BeforeOnsetFilter(); + } + + @Override + public Jwt getToken(LocalDateTime now) throws Exception { + final var onset = currentTime.minusDays(2).truncatedTo(ChronoUnit.DAYS).format(DATE_FORMATTER); + final var expiry = currentTime.plusMinutes(5).toInstant(ZoneOffset.UTC); + return jwtDecoder.decode(tokenHelper.createToken( + onset, "0", "notifyMe", "userupload", Date.from(expiry), true)); + } + + private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( + LocalDateTime start, LocalDateTime end) { + final var crypto = cryptoWrapper.getCryptoUtilV3(); + final var noncesAndNotificationKey = + crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); + byte[] preid = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-PREID".getBytes(StandardCharsets.US_ASCII), + "payload".getBytes(StandardCharsets.US_ASCII), + noncesAndNotificationKey.noncePreId)); + byte[] timekey = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), + crypto.longToBytes(3600L), + crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), + noncesAndNotificationKey.nonceTimekey)); + final var startEpochSecond = start.toInstant(ZoneOffset.UTC).toEpochMilli(); + return UserUploadPayloadOuterClass.UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(startEpochSecond) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).toEpochMilli()) + .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) + .setFake(false) + .build(); + } + +} + diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java index 15bf35e7..046939aa 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java @@ -45,6 +45,7 @@ private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( crypto.longToBytes(3600L), crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); + // TODO: What happens when we don't set fields? return UserUploadPayloadOuterClass.UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java index 8d6bbeb0..f739ae27 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java @@ -10,14 +10,16 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -27,22 +29,25 @@ @RunWith(SpringRunner.class) @SpringBootTest -@ActiveProfiles({"dev", "test-config"}) +@ActiveProfiles({"dev", "test-config", "jwt"}) +@TestPropertySource(properties = {"ws.app.jwt.publickey=classpath://generated_public_test.pem"}) public abstract class UploadInsertionFilterTest { + protected static final DateTimeFormatter DATE_FORMATTER = + DateTimeFormatter.ofPattern("YYYY-MM-dd"); + protected TokenHelper tokenHelper; @Autowired CryptoWrapper cryptoWrapper; - private TokenHelper tokenHelper; - - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("YYYY-MM-dd"); + @Autowired JwtDecoder jwtDecoder; abstract UploadVenueInfo getValidVenueInfo(); + abstract UploadVenueInfo getInvalidVenueInfo(); + abstract UploadInsertionFilter insertionFilter(); - public String getToken(LocalDateTime now) throws Exception { + public Jwt getToken(LocalDateTime now) throws Exception { final var onset = now.minusDays(5).truncatedTo(ChronoUnit.DAYS).format(DATE_FORMATTER); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); - return tokenHelper.createToken( - onset, "0", "notifyMe", "userupload", Date.from(expiry), true); + return jwtDecoder.decode(tokenHelper.createToken(onset, "0", "notifyMe", "userupload", Date.from(expiry), true)); } @Before @@ -59,7 +64,10 @@ public void testFilterValid() throws Exception { final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); final var token = getToken(now); - assertFalse(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); + assertFalse( + insertionFilter() + .filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token) + .isEmpty()); } @Test @@ -71,6 +79,9 @@ public void testFilterInvalid() throws Exception { final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); final var token = getToken(now); - assertTrue(insertionFilter().filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token).isEmpty()); + assertTrue( + insertionFilter() + .filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token) + .isEmpty()); } } From 7cf4e8d2c328ce483a77a50d9292d2beb5963fb6 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 11:14:13 +0200 Subject: [PATCH 07/19] Updated and fixed testcases --- .../IntervalThresholdFilter.java | 4 +- .../backend/ws/config/JWTValidationTest.java | 12 ++---- .../controller/NotifyMeControllerV3Test.java | 8 ++-- .../ws/insert_manager/InsertManagerTest.java | 2 +- .../BeforeOnsetFilterTest.java | 39 ++++++++++++------ .../FakeRequestFilterTest.java | 41 +++++++++++-------- .../IntervalThresholdFilterTest.java | 32 +++++++++++---- .../UploadInsertionFilterTest.java | 14 +++---- .../sdk/backend/ws/util/TokenHelper.java | 15 +++---- 9 files changed, 98 insertions(+), 69 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java index 805ee0ac..072d237f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java @@ -28,7 +28,9 @@ public List filter( return uploadVenueInfoList.stream().filter(uploadVenueInfo -> { final var start = uploadVenueInfo.getIntervalStartMs(); final var end = uploadVenueInfo.getIntervalEndMs(); - return (end - start > 0 && end - start <= 24 * 60 * 60 * 1000); + final var notNegative = end - start > 0; + final var lessThan24h = end - start <= 24 * 60 * 60 * 1000; + return (notNegative && lessThan24h); }).collect(Collectors.toList()); } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java index 3339bb7e..28d7e74c 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java @@ -3,11 +3,9 @@ import static org.junit.Assert.assertThrows; import ch.ubique.notifyme.sdk.backend.data.UUIDDataService; -import ch.ubique.notifyme.sdk.backend.ws.security.KeyVault; -import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtValidator; import ch.ubique.notifyme.sdk.backend.ws.util.TokenHelper; -import java.io.IOException; -import java.time.Duration; + +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Date; @@ -16,10 +14,8 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtException; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -46,7 +42,7 @@ public void testDecoderValid() throws Exception { final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var accessToken = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); jwtDecoder.decode(accessToken); } @@ -56,7 +52,7 @@ public void testDecoderInvalid() throws Exception { final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var accessToken = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false, Instant.now()); assertThrows(JwtException.class, () -> jwtDecoder.decode(accessToken)); } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index f480be02..e5f1b620 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -152,7 +152,7 @@ public void testUploadAndGetTraceKeys() throws Exception { final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); @@ -196,7 +196,7 @@ public void testUserUploadDuration() throws Exception { final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); final var mvcResult = @@ -223,7 +223,7 @@ public void testUserUploadValidToken() throws Exception { final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var mvcResult = mockMvc @@ -246,7 +246,7 @@ public void testUserUploadInvalidToken() throws Exception { final var expiry = LocalDateTime.now().plusMinutes(120).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false, Instant.now()); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var result = mockMvc diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java index 9c79608d..a31130fc 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java @@ -125,7 +125,7 @@ private void insertWith( final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true); + "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); insertManager.insertIntoDatabase(uploadVenueInfoList, userAgent, token, now); } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java index a52cbd44..eaf67a1c 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java @@ -1,33 +1,47 @@ package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; -import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; import org.springframework.security.oauth2.jwt.Jwt; import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.time.ZoneOffset; +import java.time.*; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.Date; +import java.util.List; public class BeforeOnsetFilterTest extends UploadInsertionFilterTest { // We don't care about the current time in the filter, we just need a common timestamp for all methods below - private static final LocalDateTime currentTime = LocalDateTime.now(); + private static final LocalDateTime currentTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); @Override - UserUploadPayloadOuterClass.UploadVenueInfo getValidVenueInfo() { + List getValidVenueInfo() { + final List venueInfoList = new ArrayList<>(); LocalDateTime start = currentTime.minusDays(1); LocalDateTime end = start.plusHours(1); - return getVenueInfo(start, end); + // venue visit one day after onset + final var venueInfoCase1 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase1); + start = currentTime.minusDays(2); + end = start.plusHours(1); + // venue visit same day as onset + final var venueInfoCase2 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase2); + return venueInfoList; } @Override - UserUploadPayloadOuterClass.UploadVenueInfo getInvalidVenueInfo() { + List getInvalidVenueInfo() { + final List venueInfoList = new ArrayList<>(); LocalDateTime start = currentTime.minusDays(3); LocalDateTime end = start.plusHours(1); - return getVenueInfo(start, end); + // venue visit one day before onset + final var venueInfo = getVenueInfo(start, end); + venueInfoList.add(venueInfo); + return venueInfoList; } @Override @@ -40,10 +54,10 @@ public Jwt getToken(LocalDateTime now) throws Exception { final var onset = currentTime.minusDays(2).truncatedTo(ChronoUnit.DAYS).format(DATE_FORMATTER); final var expiry = currentTime.plusMinutes(5).toInstant(ZoneOffset.UTC); return jwtDecoder.decode(tokenHelper.createToken( - onset, "0", "notifyMe", "userupload", Date.from(expiry), true)); + onset, "0", "notifyMe", "userupload", Date.from(expiry), true, currentTime.toInstant(ZoneOffset.UTC))); } - private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( + private UploadVenueInfo getVenueInfo( LocalDateTime start, LocalDateTime end) { final var crypto = cryptoWrapper.getCryptoUtilV3(); final var noncesAndNotificationKey = @@ -61,11 +75,10 @@ private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( crypto.longToBytes(3600L), crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); - final var startEpochSecond = start.toInstant(ZoneOffset.UTC).toEpochMilli(); - return UserUploadPayloadOuterClass.UploadVenueInfo.newBuilder() + return UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) - .setIntervalStartMs(startEpochSecond) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).toEpochMilli()) .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).toEpochMilli()) .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) .setFake(false) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java index 8f3168ab..aad96e0a 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java @@ -4,21 +4,26 @@ import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; -import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; public class FakeRequestFilterTest extends UploadInsertionFilterTest { @Override - UploadVenueInfo getValidVenueInfo() { - final UploadVenueInfo.Builder builder = getBuilder(); - return builder.setFake(false).build(); + List getValidVenueInfo() { + final var venueInfoList = new ArrayList(); + final var venueInfo = getVenueInfo(false); + venueInfoList.add(venueInfo); + return venueInfoList; } @Override - UploadVenueInfo getInvalidVenueInfo() { - final UploadVenueInfo.Builder builder = getBuilder(); - return builder.setFake(true).build(); + List getInvalidVenueInfo() { + final var venueInfoList = new ArrayList(); + final var venueInfo = getVenueInfo(true); + venueInfoList.add(venueInfo); + return venueInfoList; } @Override @@ -26,9 +31,9 @@ UploadInsertionFilter insertionFilter() { return new FakeRequestFilter(); } - private UploadVenueInfo.Builder getBuilder() { - LocalDateTime start = LocalDateTime.now(); - LocalDateTime end = start.plusMinutes(30); + private UploadVenueInfo getVenueInfo(boolean fake) { + LocalDateTime start = LocalDateTime.now(); + LocalDateTime end = start.plusMinutes(30); final var crypto = cryptoWrapper.getCryptoUtilV3(); final var noncesAndNotificationKey = crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); @@ -45,13 +50,13 @@ private UploadVenueInfo.Builder getBuilder() { crypto.longToBytes(3600L), crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); - final var builder = - UploadVenueInfo.newBuilder() - .setPreId(ByteString.copyFrom(preid)) - .setTimeKey(ByteString.copyFrom(timekey)) - .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).getEpochSecond()) - .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).getEpochSecond()) - .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)); - return builder; + return UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).toEpochMilli()) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).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/insert_manager/insertion_filters/IntervalThresholdFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java index 046939aa..4ca6aa90 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java @@ -1,25 +1,39 @@ package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; -import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; public class IntervalThresholdFilterTest extends UploadInsertionFilterTest { @Override - UserUploadPayloadOuterClass.UploadVenueInfo getValidVenueInfo() { + List getValidVenueInfo() { + final var venueInfoList = new ArrayList(); LocalDateTime start = LocalDateTime.now(); LocalDateTime end = start.plusHours(2); - return getVenueInfo(start, end); + final var venueInfo = getVenueInfo(start, end); + venueInfoList.add(venueInfo); + return venueInfoList; } @Override - UserUploadPayloadOuterClass.UploadVenueInfo getInvalidVenueInfo() { + List getInvalidVenueInfo() { + final var venueInfoList = new ArrayList(); LocalDateTime start = LocalDateTime.now(); LocalDateTime end = start.plusHours(-1); - return getVenueInfo(start, end); + // End < Start + final var venueInfoCase1 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase1); + start = LocalDateTime.now(); + end = start.plusHours(25); + // End - Start > 24 + final var venueInfoCase2 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase2); + return venueInfoList; } @Override @@ -27,7 +41,7 @@ UploadInsertionFilter insertionFilter() { return new IntervalThresholdFilter(); } - private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( + private UploadVenueInfo getVenueInfo( LocalDateTime start, LocalDateTime end) { final var crypto = cryptoWrapper.getCryptoUtilV3(); final var noncesAndNotificationKey = @@ -46,11 +60,11 @@ private UserUploadPayloadOuterClass.UploadVenueInfo getVenueInfo( crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); // TODO: What happens when we don't set fields? - return UserUploadPayloadOuterClass.UploadVenueInfo.newBuilder() + return UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) - .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).getEpochSecond()) - .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).getEpochSecond()) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).toEpochMilli()) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).toEpochMilli()) .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) .setFake(false) .build(); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java index f739ae27..eea4960d 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java @@ -16,11 +16,11 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -38,16 +38,16 @@ public abstract class UploadInsertionFilterTest { @Autowired CryptoWrapper cryptoWrapper; @Autowired JwtDecoder jwtDecoder; - abstract UploadVenueInfo getValidVenueInfo(); + abstract List getValidVenueInfo(); - abstract UploadVenueInfo getInvalidVenueInfo(); + abstract List getInvalidVenueInfo(); abstract UploadInsertionFilter insertionFilter(); public Jwt getToken(LocalDateTime now) throws Exception { final var onset = now.minusDays(5).truncatedTo(ChronoUnit.DAYS).format(DATE_FORMATTER); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); - return jwtDecoder.decode(tokenHelper.createToken(onset, "0", "notifyMe", "userupload", Date.from(expiry), true)); + return jwtDecoder.decode(tokenHelper.createToken(onset, "0", "notifyMe", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC))); } @Before @@ -58,8 +58,7 @@ public void setUp() throws Exception { @Test public void testFilterValid() throws Exception { LocalDateTime now = LocalDateTime.now(); - final List uploadVenueInfoList = new ArrayList<>(); - uploadVenueInfoList.add(getValidVenueInfo()); + final List uploadVenueInfoList = getValidVenueInfo(); final var osType = OSType.ANDROID; final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); @@ -73,8 +72,7 @@ public void testFilterValid() throws Exception { @Test public void testFilterInvalid() throws Exception { LocalDateTime now = LocalDateTime.now(); - final List uploadVenueInfoList = new ArrayList<>(); - uploadVenueInfoList.add(getInvalidVenueInfo()); + final List uploadVenueInfoList = getInvalidVenueInfo(); final var osType = OSType.ANDROID; final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/TokenHelper.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/TokenHelper.java index c8c72e88..d2c156ad 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/TokenHelper.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/util/TokenHelper.java @@ -12,6 +12,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Base64; @@ -66,14 +67,14 @@ public TokenHelper() throws Exception { } public String createToken( - String onsetDate, - String fake, - String audience, - String scope, - Date expiresAt, - boolean validSig) + String onsetDate, + String fake, + String audience, + String scope, + Date expiresAt, + boolean validSig, + Instant now) throws Exception { - final var now = LocalDateTime.now().toInstant(ZoneOffset.UTC); final var sigKey = validSig ? privateKey : loadPrivateKey(PATH_TO_SK_OTHER); return Jwts.builder() From 6ad2cd9d7f2a8777a2e6006f02691f320202b57f Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 11:57:48 +0200 Subject: [PATCH 08/19] Fixed controller tests, uncommented jwt validation, added try-catch for validation --- .../ws/controller/NotifyMeControllerV3.java | 19 ++++++++++------ .../backend/ws/config/JWTValidationTest.java | 4 ++-- .../controller/NotifyMeControllerV3Test.java | 22 +++++++++++-------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java index 1b1cb263..e12fb416 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java @@ -240,10 +240,20 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { @AuthenticationPrincipal @Documentation(description = "JWT token that can be verified by the backend server") Object principal) - throws WrongScopeException, WrongAudienceException, NotAJwtException, - UnsupportedEncodingException { + throws WrongScopeException, WrongAudienceException, NotAJwtException { + final var now = LocalDateTime.now(); + try { + requestValidator.isValid(principal); + } catch (WrongScopeException e) { + return () -> ResponseEntity.status(400).body("Wrong scope"); + } catch (WrongAudienceException e) { + return () -> ResponseEntity.status(400).body("Wrong audience"); + } catch (NotAJwtException e) { + return () -> ResponseEntity.status(400).body("Not a JWT"); + } + try { insertManager.insertIntoDatabase( userUploadPayload.getVenueInfosList(), userAgent, principal, now); @@ -251,11 +261,6 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { // TODO What to do } -// requestValidator.isValid(principal); - -// var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUploadPayload.getVenueInfosList()); -// dataService.insertTraceKey(traceKeys); - return () -> { try { DateTimeUtil.normalizeDuration(now, requestTime); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java index 28d7e74c..a862d249 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/config/JWTValidationTest.java @@ -42,7 +42,7 @@ public void testDecoderValid() throws Exception { final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var accessToken = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); jwtDecoder.decode(accessToken); } @@ -52,7 +52,7 @@ public void testDecoderInvalid() throws Exception { final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var accessToken = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), false, now.toInstant(ZoneOffset.UTC)); assertThrows(JwtException.class, () -> jwtDecoder.decode(accessToken)); } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index e5f1b620..bb01e95d 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -149,10 +149,11 @@ public void testEmptyGetTraceKeys() throws Exception { public void testUploadAndGetTraceKeys() throws Exception { final var payload = createUserUploadPayload(); final byte[] payloadBytes = payload.toByteArray(); - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var now = LocalDateTime.now(); + final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); @@ -185,7 +186,6 @@ public void testUploadAndGetTraceKeys() throws Exception { assertEquals(1, wrapper.getEventsCount()); final var event = wrapper.getEvents(0); assertNotNull(event); - // TODO: test result } @Test @@ -193,10 +193,11 @@ public void testUploadAndGetTraceKeys() throws Exception { public void testUserUploadDuration() throws Exception { final var payload = createUserUploadPayload(); final byte[] payloadBytes = payload.toByteArray(); - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var now = LocalDateTime.now(); + final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var start = LocalDateTime.now(); final var mvcResult = @@ -220,10 +221,11 @@ public void testUserUploadDuration() throws Exception { public void testUserUploadValidToken() throws Exception { final var payload = createUserUploadPayload(); final byte[] payloadBytes = payload.toByteArray(); - final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); + final var now = LocalDateTime.now(); + final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var mvcResult = mockMvc @@ -240,13 +242,15 @@ public void testUserUploadValidToken() throws Exception { @Test @Rollback + // TODO: Add more fine-grained tests for wrong audiences, scopes etc. public void testUserUploadInvalidToken() throws Exception { final var payload = createUserUploadPayload(); final byte[] payloadBytes = payload.toByteArray(); - final var expiry = LocalDateTime.now().plusMinutes(120).toInstant(ZoneOffset.UTC); + final var now = LocalDateTime.now(); + final var expiry = now.plusMinutes(120).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( - "2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), false, Instant.now()); + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), false, now.toInstant(ZoneOffset.UTC)); final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var result = mockMvc From f0521342e59c58b8052623bfe4e0c254541afd50 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 12:12:55 +0200 Subject: [PATCH 09/19] Replaced try-catch in /userupload endpoint with exceptionhandler --- .../ws/controller/NotifyMeControllerV3.java | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java index e12fb416..c57f7ec9 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java @@ -29,11 +29,13 @@ import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; import ch.ubique.notifyme.sdk.backend.ws.util.DateTimeUtil; import ch.ubique.openapi.docannotations.Documentation; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.protobuf.ByteString; import java.io.UnsupportedEncodingException; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -42,9 +44,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.CacheControl; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; @Controller @@ -226,7 +230,10 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { consumes = {"application/x-protobuf", "application/protobuf"}) @Documentation( description = "User upload of stored identities", - responses = {"200 => success", "400 => Error"}) + responses = { + "200 => success", + "400 => Bad Upload Data", + "403 => Authentication failed"}) public @ResponseBody Callable> userUpload( @Documentation(description = "Identities to upload as protobuf") @Valid @RequestBody final UserUploadPayload userUploadPayload, @@ -240,26 +247,13 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { @AuthenticationPrincipal @Documentation(description = "JWT token that can be verified by the backend server") Object principal) - throws WrongScopeException, WrongAudienceException, NotAJwtException { + throws WrongScopeException, WrongAudienceException, NotAJwtException, InsertException { final var now = LocalDateTime.now(); - try { - requestValidator.isValid(principal); - } catch (WrongScopeException e) { - return () -> ResponseEntity.status(400).body("Wrong scope"); - } catch (WrongAudienceException e) { - return () -> ResponseEntity.status(400).body("Wrong audience"); - } catch (NotAJwtException e) { - return () -> ResponseEntity.status(400).body("Not a JWT"); - } + requestValidator.isValid(principal); - try { - insertManager.insertIntoDatabase( - userUploadPayload.getVenueInfosList(), userAgent, principal, now); - } catch (InsertException e) { - // TODO What to do - } + insertManager.insertIntoDatabase(userUploadPayload.getVenueInfosList(), userAgent, principal, now); return () -> { try { @@ -270,4 +264,22 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) { return ResponseEntity.ok().build(); }; } + + @ExceptionHandler({ + InsertException.class + }) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity invalidArguments() { + return ResponseEntity.badRequest().build(); + } + + @ExceptionHandler({ + WrongScopeException.class, + WrongAudienceException.class, + NotAJwtException.class + }) + @ResponseStatus(HttpStatus.FORBIDDEN) + public ResponseEntity forbidden() { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } } From 00bbcfde69e11c020879bd353a13682982e3ed29 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 14:13:50 +0200 Subject: [PATCH 10/19] Implemented OverlappingIntervalsFilter: UploadVenueInfo objects whose intervals overlap are removed. NOTE: Currently no considerations are made w.r.t. rounding of visiting times, i.e. overlap as a result of rounding will result in the visit being filtered. --- .../OverlappingIntervalsFilter.java | 49 ++++++++++++ .../security/NotifyMeJwtRequestValidator.java | 5 +- .../OverlappingIntervalsFilterTest.java | 78 +++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java create mode 100644 notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java new file mode 100644 index 00000000..94065fef --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java @@ -0,0 +1,49 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.semver.Version; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * A person can't be in two places at the same time. UploadVenueInfo objects whose time windows + * overlap are both removed. + */ +public class OverlappingIntervalsFilter implements UploadInsertionFilter { + @Override + public List filter( + LocalDateTime now, + List uploadVenueInfoList, + OSType osType, + Version osVersion, + Version appVersion, + Object principal) + throws InsertException { + for(var i = 0; i < uploadVenueInfoList.size() - 1; i++) { + var hasOverlap = false; + final var visit = uploadVenueInfoList.get(i); + for(var j = i + 1; j < uploadVenueInfoList.size(); j++) { + if(doOverlap(visit, uploadVenueInfoList.get(j))) { + hasOverlap = true; + uploadVenueInfoList.remove(j); + j--; + } + } + if(hasOverlap) { + uploadVenueInfoList.remove(i); + i--; + } + } + return uploadVenueInfoList; + } + + // TODO: Consider rounded venue visit times - Will probably need to tolerate some amount of overlap + private boolean doOverlap( + UserUploadPayloadOuterClass.UploadVenueInfo visit1, + UserUploadPayloadOuterClass.UploadVenueInfo visit2) { + return !(visit1.getIntervalEndMs() < visit2.getIntervalStartMs() || visit2.getIntervalEndMs() < visit1.getIntervalStartMs()); + } +} diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java index 4e7224a0..668c7632 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/security/NotifyMeJwtRequestValidator.java @@ -39,7 +39,10 @@ public boolean isOnsetBefore(Object authObject, LocalDateTime dateTime) { @Override public boolean isFakeRequest(Object authObject, Object others) { - // TODO Implement + if (authObject instanceof Jwt) { + Jwt token = (Jwt) authObject; + return Boolean.TRUE.equals(token.containsClaim("fake")) && "1".equals(token.getClaim("fake")); + } return false; } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java new file mode 100644 index 00000000..b6425f70 --- /dev/null +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java @@ -0,0 +1,78 @@ +package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; + +import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import com.google.protobuf.ByteString; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +public class OverlappingIntervalsFilterTest extends UploadInsertionFilterTest { + @Override + List getValidVenueInfo() { + final var venueInfoList = new ArrayList(); + LocalDateTime start = LocalDateTime.now(); + LocalDateTime end = start.plusHours(1); + final var venueInfo1 = getVenueInfo(start, end); + venueInfoList.add(venueInfo1); + start = end.plusMinutes(1); + end = start.plusHours(1); + final var venueInfo2 = getVenueInfo(start, end); + venueInfoList.add(venueInfo2); + return venueInfoList; + } + + @Override + List getInvalidVenueInfo() { + final var venueInfoList = new ArrayList(); + final var now = LocalDateTime.now(); + LocalDateTime start = now; + LocalDateTime end = start.plusHours(1); + final var venueInfo1 = getVenueInfo(start, end); + venueInfoList.add(venueInfo1); + start = end.minusMinutes(1); + end = start.plusHours(1); + final var venueInfo2 = getVenueInfo(start, end); + venueInfoList.add(venueInfo2); + start = now.minusMinutes(59); + end = start.plusHours(1); + final var venueInfo3 = getVenueInfo(start, end); + venueInfoList.add(venueInfo3); + return venueInfoList; + } + + @Override + UploadInsertionFilter insertionFilter() { + return new OverlappingIntervalsFilter(); + } + + private UploadVenueInfo getVenueInfo( + LocalDateTime start, LocalDateTime end) { + final var crypto = cryptoWrapper.getCryptoUtilV3(); + final var noncesAndNotificationKey = + crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); + byte[] preid = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-PREID".getBytes(StandardCharsets.US_ASCII), + "payload".getBytes(StandardCharsets.US_ASCII), + noncesAndNotificationKey.noncePreId)); + byte[] timekey = + crypto.cryptoHashSHA256( + crypto.concatenate( + "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), + crypto.longToBytes(3600L), + crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), + noncesAndNotificationKey.nonceTimekey)); + return UploadVenueInfo.newBuilder() + .setPreId(ByteString.copyFrom(preid)) + .setTimeKey(ByteString.copyFrom(timekey)) + .setIntervalStartMs(start.toInstant(ZoneOffset.UTC).toEpochMilli()) + .setIntervalEndMs(end.toInstant(ZoneOffset.UTC).toEpochMilli()) + .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) + .setFake(false) + .build(); + } +} From 76ad61d7e7ed7226a4853491be4aff03eacbf12e Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 14:24:19 +0200 Subject: [PATCH 11/19] Extended InsertManagerTest to use multiple filters --- .../ws/insert_manager/InsertManagerTest.java | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java index a31130fc..a2890a2d 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java @@ -2,6 +2,9 @@ import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.FakeRequestFilter; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.IntervalThresholdFilter; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.OverlappingIntervalsFilter; import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.UploadInsertionFilter; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; @@ -21,12 +24,9 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @@ -54,7 +54,7 @@ public void testInsertEmptyList() throws Exception { final LocalDateTime now = LocalDateTime.now(); assertTrue( notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); - insertWith(null, new ArrayList<>(), now); + insertWith(new ArrayList<>(), new ArrayList<>(), now); assertTrue( notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); } @@ -80,8 +80,8 @@ public List filter( final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( createUploadVenueInfo( - now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); - insertWith(removeAll, uploadVenueInfoList, now); + now, now.plusMinutes(60), false)); + insertWith(Collections.singletonList(removeAll), uploadVenueInfoList, now); assertTrue( notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); } @@ -107,19 +107,41 @@ public List filter( final List uploadVenueInfoList = new ArrayList<>(); uploadVenueInfoList.add( createUploadVenueInfo( - now.toInstant(ZoneOffset.UTC), now.plusMinutes(60).toInstant(ZoneOffset.UTC))); - insertWith(removeNone, uploadVenueInfoList, now); - assertFalse( - notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty()); + now, now.plusMinutes(60), false)); + insertWith(Collections.singletonList(removeNone), uploadVenueInfoList, now); + assertEquals(1, + notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + } + + @Test + @Transactional + public void testAddRequestFilters() throws Exception { + final LocalDateTime now = LocalDateTime.now(); + final var venueInfoList = new ArrayList(); + final var fakeUpload = createUploadVenueInfo(now.minusDays(6), now.minusDays(5), true); + venueInfoList.add(fakeUpload); + final var negativeIntervalUpload = createUploadVenueInfo(now.minusDays(3), now.minusDays(4), 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); + venueInfoList.add(overlapIntervalUpload1); + venueInfoList.add(overlapIntervalUpload2); + final var validUpload = createUploadVenueInfo(now.minusHours(24), now.minusHours(23), 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()); } private void insertWith( - UploadInsertionFilter insertionFilter, - List uploadVenueInfoList, - LocalDateTime now) + List insertionFilterList, + List uploadVenueInfoList, + LocalDateTime now) throws Exception { - if (insertionFilter != null) { - insertManager.addFilter(insertionFilter); + + for(var insertionFilter: insertionFilterList) { + if (insertionFilter != null) { + insertManager.addFilter(insertionFilter); + } } final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC); @@ -129,7 +151,9 @@ private void insertWith( insertManager.insertIntoDatabase(uploadVenueInfoList, userAgent, token, now); } - private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end) { + private UploadVenueInfo createUploadVenueInfo(LocalDateTime start, LocalDateTime end, boolean fake) { + final var startInstant = start.toInstant(ZoneOffset.UTC); + final var endInstant = end.toInstant(ZoneOffset.UTC); final var crypto = cryptoWrapper.getCryptoUtilV3(); final var noncesAndNotificationKey = crypto.getNoncesAndNotificationKey(crypto.createNonce(256)); @@ -144,15 +168,15 @@ private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end) { crypto.concatenate( "CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII), crypto.longToBytes(3600L), - crypto.longToBytes(start.getEpochSecond()), + crypto.longToBytes(startInstant.getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); return UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) - .setIntervalStartMs(start.getEpochSecond()) - .setIntervalEndMs(end.getEpochSecond()) + .setIntervalStartMs(startInstant.toEpochMilli()) + .setIntervalEndMs(endInstant.toEpochMilli()) .setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey)) - .setFake(false) + .setFake(fake) .build(); } } From 7443f4634179b546e13084eeabb7a09bbdd2346f Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 14:53:08 +0200 Subject: [PATCH 12/19] Implemented e2e tests for controller to test visit filtering --- .../sdk/backend/ws/config/WSBaseConfig.java | 11 ++- .../ws/insert_manager/InsertManager.java | 8 +- .../controller/NotifyMeControllerV3Test.java | 99 +++++++++++-------- 3 files changed, 70 insertions(+), 48 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java index 9e0f2b71..6e751945 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java @@ -26,6 +26,10 @@ import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebController; import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebCriticalEventController; import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.BeforeOnsetFilter; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.FakeRequestFilter; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.IntervalThresholdFilter; +import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.OverlappingIntervalsFilter; import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtRequestValidator; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator; import ch.ubique.notifyme.sdk.backend.ws.service.PhoneHeartbeatSilentPush; @@ -174,7 +178,12 @@ public InsertManager insertManager( final CryptoWrapper cryptoWrapper, final NotifyMeDataServiceV3 notifyMeDataServiceV3 ) { - return new InsertManager(cryptoWrapper, notifyMeDataServiceV3); + final var insertManager = new InsertManager(cryptoWrapper, notifyMeDataServiceV3); + insertManager.addFilter(new FakeRequestFilter()); + insertManager.addFilter(new IntervalThresholdFilter()); + insertManager.addFilter(new BeforeOnsetFilter()); + insertManager.addFilter(new OverlappingIntervalsFilter()); + return insertManager; } @Bean diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java index 3c0119aa..e76c64e4 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java @@ -2,7 +2,6 @@ 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.insert_manager.insertion_filters.UploadInsertionFilter; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; @@ -38,14 +37,15 @@ public void insertIntoDatabase( LocalDateTime now ) throws InsertException { if (uploadVenueInfoList != null && !uploadVenueInfoList.isEmpty()) { - final var traceKeys = filterUpload(uploadVenueInfoList, header, principal, now); + final var filteredVenueInfoList = filterUpload(uploadVenueInfoList, header, principal, now); + final var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(filteredVenueInfoList); if (!traceKeys.isEmpty()) { notifyMeDataServiceV3.insertTraceKey(traceKeys); } } } - private List filterUpload(List uploadVenueInfoList, String header, Object principal, LocalDateTime now) throws InsertException { + private List filterUpload(List uploadVenueInfoList, String header, Object principal, LocalDateTime now) throws InsertException { var headerParts = header.split(";"); if (headerParts.length < 5) { headerParts = @@ -64,7 +64,7 @@ private List filterUpload(List uploadVenueInfoList, S for (UploadInsertionFilter insertionFilter: filterList) { venueInfoList = insertionFilter.filter(now, venueInfoList, osType, osVersion, appVersion, principal); } - return cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(venueInfoList); + return venueInfoList; } /** diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index bb01e95d..b4e4b26f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -19,11 +19,11 @@ import com.google.protobuf.ByteString; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import java.util.Date; import org.junit.Before; import org.junit.Test; @@ -147,9 +147,9 @@ public void testEmptyGetTraceKeys() throws Exception { @Test @Rollback public void testUploadAndGetTraceKeys() throws Exception { - final var payload = createUserUploadPayload(); - final byte[] payloadBytes = payload.toByteArray(); final var now = LocalDateTime.now(); + final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); + final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( @@ -190,10 +190,10 @@ public void testUploadAndGetTraceKeys() throws Exception { @Test @Rollback - public void testUserUploadDuration() throws Exception { - final var payload = createUserUploadPayload(); - final byte[] payloadBytes = payload.toByteArray(); + public void testUserUploadValidToken() throws Exception { final var now = LocalDateTime.now(); + final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); + final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( @@ -212,41 +212,16 @@ public void testUserUploadDuration() throws Exception { .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); final var duration = start.until(LocalDateTime.now(), ChronoUnit.MILLIS); - + assertEquals(2, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); assertTrue(requestTime <= duration); } @Test @Rollback - public void testUserUploadValidToken() throws Exception { - final var payload = createUserUploadPayload(); - final byte[] payloadBytes = payload.toByteArray(); + public void testUserUploadInvalidTokenSig() throws Exception { final var now = LocalDateTime.now(); - final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); - final var token = - tokenHelper.createToken( - "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); - final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; - final var mvcResult = - mockMvc - .perform( - post("/v3/userupload") - .contentType("application/x-protobuf") - .header("Authorization", "Bearer " + token) - .header("User-Agent", userAgent) - .content(payloadBytes)) - .andExpect(request().asyncStarted()) - .andReturn(); - mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); - } - - @Test - @Rollback - // TODO: Add more fine-grained tests for wrong audiences, scopes etc. - public void testUserUploadInvalidToken() throws Exception { - final var payload = createUserUploadPayload(); + final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); final byte[] payloadBytes = payload.toByteArray(); - final var now = LocalDateTime.now(); final var expiry = now.plusMinutes(120).toInstant(ZoneOffset.UTC); final var token = tokenHelper.createToken( @@ -267,27 +242,65 @@ public void testUserUploadInvalidToken() throws Exception { assertTrue(authenticationError.contains("Bearer")); } + @Test + @Rollback + public void testUserUploadVisitFilters() throws Exception { + final var now = LocalDateTime.now(); + final var fakeUpload = getUploadVenueInfo(now.minusDays(3), now.minusHours(60), true); + final var invalidIntervalUpload = getUploadVenueInfo(now.minusHours(59), now.minusHours(34), false); + final var validUpload = getUploadVenueInfo(now.minusHours(12), now.minusHours(10), false); + final var payload = getUserUploadPayload(fakeUpload, invalidIntervalUpload, validUpload); + final byte[] payloadBytes = payload.toByteArray(); + final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); + final var token = + tokenHelper.createToken( + "2021-04-29", "0", "checkin", "userupload", Date.from(expiry), true, now.toInstant(ZoneOffset.UTC)); + final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29"; + final var start = LocalDateTime.now(); + final var mvcResult = + mockMvc + .perform( + post("/v3/userupload") + .contentType("application/x-protobuf") + .header("Authorization", "Bearer " + token) + .header("User-Agent", userAgent) + .content(payloadBytes)) + .andExpect(request().asyncStarted()) + .andReturn(); + mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); + final var duration = start.until(LocalDateTime.now(), ChronoUnit.MILLIS); + assertEquals(2, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + assertTrue(requestTime <= duration); + } + /** * Creates simple user upload payload with one venue info * * @return */ - private UserUploadPayload createUserUploadPayload() { - final var to = LocalDateTime.now().toInstant(ZoneOffset.UTC); - final var from = to.minus(Duration.ofHours(1)); + private UserUploadPayload createUserUploadPayload(LocalDateTime start, LocalDateTime end) { + UploadVenueInfo venueInfo = getUploadVenueInfo(start, end, false); + return getUserUploadPayload(venueInfo); + } + + private UserUploadPayload getUserUploadPayload(UploadVenueInfo... venueInfo) { + final var userUpload = + UserUploadPayload.newBuilder().setVersion(3).addAllVenueInfos(Arrays.asList(venueInfo)).build(); + return userUpload; + } + + private UploadVenueInfo getUploadVenueInfo(LocalDateTime start, LocalDateTime end, boolean fake) { + final var from = start.toInstant(ZoneOffset.UTC); + final var to = end.toInstant(ZoneOffset.UTC); var venueInfo = UploadVenueInfo.newBuilder() - .setFake(false) + .setFake(fake) .setPreId(ByteString.copyFromUtf8("preId")) .setNotificationKey(ByteString.copyFromUtf8("notificationKey")) .setTimeKey(ByteString.copyFromUtf8("timeKey")) .setIntervalStartMs(from.toEpochMilli()) .setIntervalEndMs(to.toEpochMilli()) .build(); - - final var userUpload = - UserUploadPayload.newBuilder().setVersion(3).addVenueInfos(venueInfo).build(); - - return userUpload; + return venueInfo; } } From 055e98e9a86046b060575fd7cc77bddc85b795b4 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 15:26:05 +0200 Subject: [PATCH 13/19] Fixed incorrect controller unit test --- .../OverlappingIntervalsFilter.java | 1 - .../controller/NotifyMeControllerV3Test.java | 29 ++++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java index 94065fef..10ba9f83 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java @@ -40,7 +40,6 @@ public List filter( return uploadVenueInfoList; } - // TODO: Consider rounded venue visit times - Will probably need to tolerate some amount of overlap private boolean doOverlap( UserUploadPayloadOuterClass.UploadVenueInfo visit1, UserUploadPayloadOuterClass.UploadVenueInfo visit2) { diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index b4e4b26f..1f4acaba 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -25,6 +25,9 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,14 +36,14 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.test.annotation.Rollback; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles({"dev", "jwt"}) +@ActiveProfiles({"dev", "jwt", "test-config"}) @TestPropertySource( properties = { "ws.app.jwt.publickey=classpath://generated_public_test.pem", @@ -124,7 +127,7 @@ public void testGetTraceKeysJson() throws Exception { } @Test - @Rollback + @Transactional public void testEmptyGetTraceKeys() throws Exception { final MockHttpServletResponse response = mockMvc @@ -145,7 +148,7 @@ public void testEmptyGetTraceKeys() throws Exception { } @Test - @Rollback + @Transactional public void testUploadAndGetTraceKeys() throws Exception { final var now = LocalDateTime.now(); final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); @@ -189,9 +192,10 @@ public void testUploadAndGetTraceKeys() throws Exception { } @Test - @Rollback + @Transactional public void testUserUploadValidToken() throws Exception { - final var now = LocalDateTime.now(); + final var now = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS); + final var initSize = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size(); final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); @@ -212,12 +216,13 @@ public void testUserUploadValidToken() throws Exception { .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); final var duration = start.until(LocalDateTime.now(), ChronoUnit.MILLIS); - assertEquals(2, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + final var traceKeys = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)); + assertEquals(initSize + 1, traceKeys.size()); assertTrue(requestTime <= duration); } @Test - @Rollback + @Transactional public void testUserUploadInvalidTokenSig() throws Exception { final var now = LocalDateTime.now(); final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); @@ -243,9 +248,10 @@ public void testUserUploadInvalidTokenSig() throws Exception { } @Test - @Rollback + @Transactional public void testUserUploadVisitFilters() throws Exception { - final var now = LocalDateTime.now(); + final var now = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS); + final var initSize = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size(); final var fakeUpload = getUploadVenueInfo(now.minusDays(3), now.minusHours(60), true); final var invalidIntervalUpload = getUploadVenueInfo(now.minusHours(59), now.minusHours(34), false); final var validUpload = getUploadVenueInfo(now.minusHours(12), now.minusHours(10), false); @@ -269,7 +275,8 @@ public void testUserUploadVisitFilters() throws Exception { .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()); final var duration = start.until(LocalDateTime.now(), ChronoUnit.MILLIS); - assertEquals(2, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size()); + final var traceKeys = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)); + assertEquals(initSize + 1, traceKeys.size()); assertTrue(requestTime <= duration); } From c4ea410a86f28a67af0d0b8321795b96987a84e2 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 12 May 2021 15:50:18 +0200 Subject: [PATCH 14/19] Decreased allowed time interval length in intervalthreshold filter to 1h & added comments --- .../ws/insert_manager/InsertManager.java | 38 ++++++++++++++----- .../IntervalThresholdFilter.java | 9 ++--- .../controller/NotifyMeControllerV3Test.java | 6 +-- .../IntervalThresholdFilterTest.java | 13 +++++-- .../UploadInsertionFilterTest.java | 7 ++-- .../swagger/swagger.yaml | 6 ++- 6 files changed, 53 insertions(+), 26 deletions(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java index e76c64e4..00f5381b 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java @@ -26,10 +26,24 @@ public InsertManager(CryptoWrapper cryptoWrapper, NotifyMeDataServiceV3 notifyMe this.notifyMeDataServiceV3 = notifyMeDataServiceV3; } + /** + * Adds a filter to the list of filters to be applied to a {@link UploadVenueInfo} object before inserting it + * into the database as a {@link ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey}. + * @param filter to be added to the filter list. The filter method must return a filtered list of VenueInfo's + */ public void addFilter(UploadInsertionFilter filter) { this.filterList.add(filter); } + /** + * Applies the stored list of filters, transforms any remaining venueInfo's into trace keys, and stores them to the + * database. + * @param uploadVenueInfoList List of UploadVenueInfo objects to be stored to the database + * @param header User-Agent header as included in the user-upload request + * @param principal the authorization context which belongs to the uploaded keys. This will usually be a JWT token. + * @param now Current timestamp + * @throws InsertException + */ public void insertIntoDatabase( List uploadVenueInfoList, String header, @@ -49,7 +63,7 @@ private List filterUpload(List uploadVenueInfo var headerParts = header.split(";"); if (headerParts.length < 5) { headerParts = - List.of("org.example.dp3t", "1.0.0", "0", "Android", "29").toArray(new String[0]); + List.of("org.example.notifyMe", "1.0.0", "0", "Android", "29").toArray(new String[0]); logger.error("We received an invalid header, setting default."); } @@ -67,13 +81,11 @@ private List filterUpload(List uploadVenueInfo return venueInfoList; } - /** - * Extracts the {@link OSType} from the osString that is given by the client request. - * - * @param osString - * @return - */ - private OSType exctractOS(String osString) { + /** + * Extracts the {@link OSType} from the osString that is given by the client request's + * user-agent header. + */ + private OSType exctractOS(String osString) { var result = OSType.ANDROID; switch (osString.toLowerCase()) { case "ios": @@ -87,10 +99,18 @@ private OSType exctractOS(String osString) { return result; } - private Version extractOsVersion(String osVersionString) { + /** + * Extracts the {@link Version} from the osVersionString that is given by the client request's + * user-agent header. + */ + private Version extractOsVersion(String osVersionString) { return new Version(osVersionString); } + /** + * Extracts the {@link Version} from the osAppVersionString and osMetaInfo that are given by the client request's + * user-agent header. + */ private Version extractAppVersion(String osAppVersionString, String osMetaInfo) { return new Version(osAppVersionString + "+" + osMetaInfo); } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java index 072d237f..863f6831 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java @@ -11,9 +11,8 @@ import java.util.stream.Collectors; /** - * TODO: What's the minimum value we can use here? - * The app doesn't support store visit of longer than 24 hours (users are automatically checked out). - * UploadVenueInfo objects that break the interval threshold of (0,24) are dropped. + * The app doesn't support store visit of longer than 1 hour (users are automatically checked out). + * UploadVenueInfo objects that break the interval threshold of (0,1) are dropped. */ public class IntervalThresholdFilter implements UploadInsertionFilter { @Override @@ -29,8 +28,8 @@ public List filter( final var start = uploadVenueInfo.getIntervalStartMs(); final var end = uploadVenueInfo.getIntervalEndMs(); final var notNegative = end - start > 0; - final var lessThan24h = end - start <= 24 * 60 * 60 * 1000; - return (notNegative && lessThan24h); + final var lessThan1h = end - start <= 60 * 60 * 1000; + return (notNegative && lessThan1h); }).collect(Collectors.toList()); } } diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java index 1f4acaba..43a6cb1a 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3Test.java @@ -151,7 +151,7 @@ public void testEmptyGetTraceKeys() throws Exception { @Transactional public void testUploadAndGetTraceKeys() throws Exception { final var now = LocalDateTime.now(); - final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); + final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(23)); final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = @@ -196,7 +196,7 @@ public void testUploadAndGetTraceKeys() throws Exception { public void testUserUploadValidToken() throws Exception { final var now = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS); final var initSize = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size(); - final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(12)); + final var payload = createUserUploadPayload(now.minusDays(1), now.minusHours(23)); final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); final var token = @@ -254,7 +254,7 @@ public void testUserUploadVisitFilters() throws Exception { final var initSize = notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size(); final var fakeUpload = getUploadVenueInfo(now.minusDays(3), now.minusHours(60), true); final var invalidIntervalUpload = getUploadVenueInfo(now.minusHours(59), now.minusHours(34), false); - final var validUpload = getUploadVenueInfo(now.minusHours(12), now.minusHours(10), false); + final var validUpload = getUploadVenueInfo(now.minusHours(12), now.minusHours(11), false); final var payload = getUserUploadPayload(fakeUpload, invalidIntervalUpload, validUpload); final byte[] payloadBytes = payload.toByteArray(); final var expiry = now.plusMinutes(5).toInstant(ZoneOffset.UTC); diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java index 4ca6aa90..45f03c18 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java @@ -14,9 +14,15 @@ public class IntervalThresholdFilterTest extends UploadInsertionFilterTest { List getValidVenueInfo() { final var venueInfoList = new ArrayList(); LocalDateTime start = LocalDateTime.now(); - LocalDateTime end = start.plusHours(2); - final var venueInfo = getVenueInfo(start, end); - venueInfoList.add(venueInfo); + LocalDateTime end = start.plusMinutes(30); + // Not an edge case + final var venueInfoCase1 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase1); + start = LocalDateTime.now(); + end = start.plusHours(1); + // Exactly 1 hour + final var venueInfoCase2 = getVenueInfo(start, end); + venueInfoList.add(venueInfoCase2); return venueInfoList; } @@ -59,7 +65,6 @@ private UploadVenueInfo getVenueInfo( crypto.longToBytes(3600L), crypto.longToBytes(start.toInstant(ZoneOffset.UTC).getEpochSecond()), noncesAndNotificationKey.nonceTimekey)); - // TODO: What happens when we don't set fields? return UploadVenueInfo.newBuilder() .setPreId(ByteString.copyFrom(preid)) .setTimeKey(ByteString.copyFrom(timekey)) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java index eea4960d..2e89fd07 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java @@ -24,8 +24,7 @@ import java.util.Date; import java.util.List; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @@ -63,10 +62,10 @@ public void testFilterValid() throws Exception { final var osVersion = new Version("29"); final var appVersion = new Version("1.0.0+0"); final var token = getToken(now); - assertFalse( + assertEquals(uploadVenueInfoList.size(), insertionFilter() .filter(now, uploadVenueInfoList, osType, osVersion, appVersion, token) - .isEmpty()); + .size()); } @Test diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml b/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml index 61333ac1..2fb277e4 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/swagger/swagger.yaml @@ -230,7 +230,11 @@ paths: schema: type: string '400': - description: Error + description: Bad Upload Data + headers: { + } + '403': + description: Authentication failed headers: { } requestBody: From 75d0aea45c9801c0771eff841ac55bfed0a5b705 Mon Sep 17 00:00:00 2001 From: alig Date: Tue, 18 May 2021 14:48:14 +0200 Subject: [PATCH 15/19] Disable CSRF. --- .../ch/ubique/notifyme/sdk/backend/ws/config/JwtConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/JwtConfig.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/JwtConfig.java index 19983fa5..0b564643 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/JwtConfig.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/JwtConfig.java @@ -37,7 +37,7 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; @Configuration -@EnableWebSecurity(debug = false) +@EnableWebSecurity @Profile(value = "jwt") public class JwtConfig extends WebSecurityConfigurerAdapter { @@ -54,6 +54,10 @@ protected void configure(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() + .csrf() + .disable() + .cors() + .and() .authorizeRequests() .antMatchers(HttpMethod.POST, "/v3/userupload", "/v3/traceKeys") .authenticated() From 3589d6a92ad5342cc30cc1bafc6be6000d24d6f8 Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 18 May 2021 15:52:36 +0200 Subject: [PATCH 16/19] renamed insertion_manager and insertion_filters packages --- .../notifyme/sdk/backend/ws/config/WSBaseConfig.java | 10 +++++----- .../backend/ws/controller/NotifyMeControllerV3.java | 8 ++------ .../InsertException.java | 2 +- .../InsertManager.java | 4 ++-- .../ws/{insert_manager => insertmanager}/OSType.java | 2 +- .../insertfilters}/BeforeOnsetFilter.java | 6 +++--- .../insertfilters}/FakeRequestFilter.java | 6 +++--- .../insertfilters}/IntervalThresholdFilter.java | 7 +++---- .../insertfilters}/OverlappingIntervalsFilter.java | 6 +++--- .../insertfilters}/UploadInsertionFilter.java | 9 ++++----- .../InsertManagerTest.java | 10 +++++----- .../insertfilters}/BeforeOnsetFilterTest.java | 2 +- .../insertfilters}/FakeRequestFilterTest.java | 2 +- .../insertfilters}/IntervalThresholdFilterTest.java | 2 +- .../insertfilters}/OverlappingIntervalsFilterTest.java | 2 +- .../insertfilters}/UploadInsertionFilterTest.java | 5 ++--- 16 files changed, 38 insertions(+), 45 deletions(-) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager => insertmanager}/InsertException.java (69%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager => insertmanager}/InsertManager.java (96%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager => insertmanager}/OSType.java (83%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/BeforeOnsetFilter.java (86%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/FakeRequestFilter.java (81%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/IntervalThresholdFilter.java (83%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/OverlappingIntervalsFilter.java (87%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/UploadInsertionFilter.java (82%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager => insertmanager}/InsertManagerTest.java (94%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/BeforeOnsetFilterTest.java (98%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/FakeRequestFilterTest.java (96%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/IntervalThresholdFilterTest.java (97%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/OverlappingIntervalsFilterTest.java (97%) rename notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/{insert_manager/insertion_filters => insertmanager/insertfilters}/UploadInsertionFilterTest.java (94%) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java index 6e751945..f56cf25f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/config/WSBaseConfig.java @@ -25,11 +25,11 @@ import ch.ubique.notifyme.sdk.backend.ws.controller.NotifyMeControllerV3; import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebController; import ch.ubique.notifyme.sdk.backend.ws.controller.web.WebCriticalEventController; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.BeforeOnsetFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.FakeRequestFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.IntervalThresholdFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.OverlappingIntervalsFilter; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertManager; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.BeforeOnsetFilter; +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; import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtRequestValidator; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator; import ch.ubique.notifyme.sdk.backend.ws.service.PhoneHeartbeatSilentPush; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java index c57f7ec9..fe9194f8 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/controller/NotifyMeControllerV3.java @@ -20,8 +20,8 @@ import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEvent; import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEvent.Builder; import ch.ubique.notifyme.sdk.backend.model.v3.ProblematicEventWrapperOuterClass.ProblematicEventWrapper; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertManager; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator.NotAJwtException; import ch.ubique.notifyme.sdk.backend.ws.security.RequestValidator.WrongAudienceException; @@ -29,13 +29,10 @@ import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; import ch.ubique.notifyme.sdk.backend.ws.util.DateTimeUtil; import ch.ubique.openapi.docannotations.Documentation; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.protobuf.ByteString; import java.io.UnsupportedEncodingException; import java.time.Duration; -import java.time.Instant; import java.time.LocalDateTime; -import java.time.format.DateTimeParseException; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -48,7 +45,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; @Controller diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertException.java similarity index 69% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertException.java index abd10811..fa56aa10 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertException.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertException.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager; public abstract class InsertException extends Exception { private static final long serialVersionUID = 6476089262577182680L; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManager.java similarity index 96% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManager.java index 00f5381b..46ee947c 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManager.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManager.java @@ -1,8 +1,8 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager; import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.UploadInsertionFilter; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.UploadInsertionFilter; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; import org.slf4j.Logger; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/OSType.java similarity index 83% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/OSType.java index c70579da..253b9abf 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/OSType.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/OSType.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager; public enum OSType { ANDROID, diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilter.java similarity index 86% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilter.java index ffacca6f..3614389d 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilter.java @@ -1,8 +1,8 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.security.NotifyMeJwtRequestValidator; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilter.java similarity index 81% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilter.java index f1ef9a7c..8eb98b14 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilter.java @@ -1,8 +1,8 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import java.time.LocalDateTime; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java similarity index 83% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java index 863f6831..968c5b11 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java @@ -1,11 +1,10 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; -import java.time.Instant; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilter.java similarity index 87% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilter.java index 10ba9f83..0b2cd6ea 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilter.java @@ -1,8 +1,8 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import java.time.LocalDateTime; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilter.java similarity index 82% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilter.java index bdf57c34..aea60991 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilter.java @@ -1,13 +1,12 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; 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.insert_manager.InsertException; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.InsertManager; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertException; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.InsertManager; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; -import java.time.Instant; import java.time.LocalDateTime; import java.util.List; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java similarity index 94% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java index a2890a2d..80acdc0f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/InsertManagerTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/InsertManagerTest.java @@ -1,11 +1,11 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager; import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.FakeRequestFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.IntervalThresholdFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.OverlappingIntervalsFilter; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters.UploadInsertionFilter; +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; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.UploadInsertionFilter; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; import ch.ubique.notifyme.sdk.backend.ws.util.TokenHelper; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilterTest.java similarity index 98% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilterTest.java index eaf67a1c..8c42f4f8 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/BeforeOnsetFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/BeforeOnsetFilterTest.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilterTest.java similarity index 96% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilterTest.java index aad96e0a..b26419df 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/FakeRequestFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/FakeRequestFilterTest.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilterTest.java similarity index 97% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilterTest.java index 45f03c18..83382778 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/IntervalThresholdFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilterTest.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilterTest.java similarity index 97% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilterTest.java index b6425f70..d11f6ad2 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/OverlappingIntervalsFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/OverlappingIntervalsFilterTest.java @@ -1,4 +1,4 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; import com.google.protobuf.ByteString; diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilterTest.java similarity index 94% rename from notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java rename to notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilterTest.java index 2e89fd07..38583768 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insert_manager/insertion_filters/UploadInsertionFilterTest.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/test/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/UploadInsertionFilterTest.java @@ -1,7 +1,7 @@ -package ch.ubique.notifyme.sdk.backend.ws.insert_manager.insertion_filters; +package ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters; import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo; -import ch.ubique.notifyme.sdk.backend.ws.insert_manager.OSType; +import ch.ubique.notifyme.sdk.backend.ws.insertmanager.OSType; import ch.ubique.notifyme.sdk.backend.ws.semver.Version; import ch.ubique.notifyme.sdk.backend.ws.util.CryptoWrapper; import ch.ubique.notifyme.sdk.backend.ws.util.TokenHelper; @@ -16,7 +16,6 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; From 2c32fc42e18e723b479841df3a6ec7e1760efc6c Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 18 May 2021 15:56:47 +0200 Subject: [PATCH 17/19] Corrected IntervalThresholdFilter comment --- .../ws/insertmanager/insertfilters/IntervalThresholdFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java index 968c5b11..4cbf1d83 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java @@ -10,7 +10,7 @@ import java.util.stream.Collectors; /** - * The app doesn't support store visit of longer than 1 hour (users are automatically checked out). + * The app uploads VenueInfo objects that last at most 1 hour. * UploadVenueInfo objects that break the interval threshold of (0,1) are dropped. */ public class IntervalThresholdFilter implements UploadInsertionFilter { From 058448d6e1a3ae13b84a9822ecbf72fdcc1c4fcd Mon Sep 17 00:00:00 2001 From: lmeinen Date: Tue, 18 May 2021 16:00:20 +0200 Subject: [PATCH 18/19] Corrected IntervalThresholdFilter comment --- .../ws/insertmanager/insertfilters/IntervalThresholdFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java index 4cbf1d83..28705a2f 100644 --- a/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java +++ b/notifyme-sdk-backend/notifyme-sdk-backend-ws/src/main/java/ch/ubique/notifyme/sdk/backend/ws/insertmanager/insertfilters/IntervalThresholdFilter.java @@ -10,7 +10,7 @@ import java.util.stream.Collectors; /** - * The app uploads VenueInfo objects that last at most 1 hour. + * The app uploads VenueInfo objects that span at most 1 hour. * UploadVenueInfo objects that break the interval threshold of (0,1) are dropped. */ public class IntervalThresholdFilter implements UploadInsertionFilter { From 5e555bb25fafb20017b3ca027610f772e768870f Mon Sep 17 00:00:00 2001 From: lmeinen Date: Wed, 19 May 2021 15:38:58 +0200 Subject: [PATCH 19/19] 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()); }