Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/verification #12

Open
wants to merge 19 commits into
base: feature/userupload
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -46,24 +53,31 @@ public void insertTraceKey(TraceKey traceKey) {

@Override
@Transactional(readOnly = true)
public List<TraceKey> findTraceKeys(Instant after) {
public List<TraceKey> findTraceKeys(Instant before, Instant after) {
lmeinen marked this conversation as resolved.
Show resolved Hide resolved
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<TraceKey> 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);
}

Expand All @@ -80,15 +94,15 @@ public void insertTraceKey(List<TraceKey> 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()));
lmeinen marked this conversation as resolved.
Show resolved Hide resolved
}
params.addValue("encrypted_associated_data", traceKey.getEncryptedAssociatedData());
params.addValue("cipher_text_nonce", traceKey.getCipherTextNonce());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TraceKey> findTraceKeys(Instant before, Instant after);

/**
* Wrapper around findTraceKeys where before is set to the end of the previous bucket
*
* @param after
* @return
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;

@Configuration
@EnableWebSecurity(debug = false)
@EnableWebSecurity
@Profile(value = "jwt")
public class JwtConfig extends WebSecurityConfigurerAdapter {

Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +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.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;
Expand Down Expand Up @@ -168,6 +173,19 @@ public UUIDDataService uuidDataService() {
return new UUIDDataServiceImpl(dataSource());
}

@Bean
public InsertManager insertManager(
final CryptoWrapper cryptoWrapper,
final NotifyMeDataServiceV3 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
public NotifyMeControllerV2 notifyMeControllerV2(
final NotifyMeDataServiceV2 notifyMeDataService,
Expand All @@ -184,13 +202,15 @@ public NotifyMeControllerV2 notifyMeControllerV2(
@Bean
public NotifyMeControllerV3 notifyMeControllerV3(
NotifyMeDataServiceV3 notifyMeDataServiceV3,
InsertManager insertManager,
PushRegistrationDataService pushRegistrationDataService,
UUIDDataService uuidDataService,
RequestValidator requestValidator,
CryptoWrapper cryptoWrapper,
String revision) {
return new NotifyMeControllerV3(
notifyMeDataServiceV3,
insertManager,
pushRegistrationDataService,
uuidDataService,
requestValidator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.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;
Expand All @@ -39,16 +41,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.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")
Expand All @@ -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;
Expand All @@ -70,6 +68,7 @@ public class NotifyMeControllerV3 {

public NotifyMeControllerV3(
NotifyMeDataServiceV3 dataService,
InsertManager insertManager,
PushRegistrationDataService pushRegistrationDataService,
UUIDDataService uuidDataService,
RequestValidator requestValidator,
Expand All @@ -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;
Expand Down Expand Up @@ -226,21 +226,30 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) {
consumes = {"application/x-protobuf", "application/protobuf"})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/notifyme-app/notifyme-sdk-backend/pull/12/files#diff-3831def3db4a6233be7fc0827a926221afb47b5e530e79a84b859067c8caa942R191 this request must be protected or removed for now, otherwise any traceKeys can be uploaded.

@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<ResponseEntity<String>> 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)
throws WrongScopeException, WrongAudienceException, NotAJwtException,
UnsupportedEncodingException {
throws WrongScopeException, WrongAudienceException, NotAJwtException, InsertException {

final var now = LocalDateTime.now();

// requestValidator.isValid(principal);
requestValidator.isValid(principal);

var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUploadPayload);
dataService.insertTraceKey(traceKeys);
insertManager.insertIntoDatabase(userUploadPayload.getVenueInfosList(), userAgent, principal, now);

return () -> {
try {
Expand All @@ -251,4 +260,22 @@ private ProblematicEvent mapTraceKeyToProblematicEvent(TraceKey t) {
return ResponseEntity.ok().build();
};
}

@ExceptionHandler({
InsertException.class
})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<Object> invalidArguments() {
return ResponseEntity.badRequest().build();
}

@ExceptionHandler({
WrongScopeException.class,
WrongAudienceException.class,
NotAJwtException.class
})
@ResponseStatus(HttpStatus.FORBIDDEN)
public ResponseEntity<Object> forbidden() {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ch.ubique.notifyme.sdk.backend.ws.insertmanager;

public abstract class InsertException extends Exception {
private static final long serialVersionUID = 6476089262577182680L;
}
Loading