Skip to content

Commit

Permalink
Merge pull request #209 from DP-3T/develop
Browse files Browse the repository at this point in the history
Version 1.0.5
  • Loading branch information
simonroesch authored Sep 24, 2020
2 parents a47fdad + 76024dc commit e4d7188
Show file tree
Hide file tree
Showing 18 changed files with 280 additions and 35 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/bintray-develop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Upload AAR to bintray

on:
push:
branches: [ develop ]

jobs:
build:
name: "Upload AAR to bintray"
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Upload
run: cd dp3t-sdk; ./gradlew bintrayUpload -PbintrayUser=${{secrets.BINTRAY_USER}} -PbintrayApikey=${{secrets.BINTRAY_APIKEY}} -PbintrayVersionSuffix=-dev-$GITHUB_RUN_NUMBER
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# IntelliJ files
/.idea
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog for DP3T-SDK Android

## version 1.0.5 (24.9.2020)

- support location less scanning on Android 11
- fix state update bug when EN are activated/deactivated outside of the app
- update targetSdk to 30, use gradle 6.6.1 and Android-Plugin 4.0.1
- fix https://github.com/DP-3T/dp3t-sdk-android/issues/206

## version 1.0.4 (25.8.2020)

- exposed days are now deleted 14 days after reporting the exposureDay (before they were deleted 10 days after the exposure which could be only 1 day after reporting)
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,5 +156,16 @@ DP3T.sync(getContext());
Make sure you do not call this method on the UI thread, because it will perform the sync synchronously.
Due to rate limits on the provideDiagnosisKeys() the sync can be execute only in a very restricted manner.

## Apps using the DP3T-SDK for Android
Name | Country | Source code | Store | Release-Date
---- | ----------- | ------------- | ------------- | -------------
SwissCovid | Switzerland | [Github](https://github.com/DP-3T/dp3t-app-android-ch) | [PlayStore](https://play.google.com/store/apps/details?id=ch.admin.bag.dp3t) | 25. Mai 2020
ASI | Ecuador | [minka.gob.ec](https://minka.gob.ec/asi-ecuador/android) | [PlayStore](https://play.google.com/store/apps/details?id=ec.gob.asi.android) | 2. August 2020
Hoia | Estonia | [koodivaramu.eesti.ee](https://koodivaramu.eesti.ee/tehik/hoia/dp3t-app-android) | [PlayStore](https://play.google.com/store/apps/details?id=ee.tehik.hoia) | 18. August 2020
STAYAWAY COVID | Portugal | [Github](https://github.com/stayawayinesctec/stayaway-app) | [PlayStore](https://play.google.com/store/apps/details?id=fct.inesctec.stayaway) | 28. August 2020
Radar COVID | Spain | [Github](https://github.com/RadarCOVID/radar-covid-android) | [PlayStore](https://play.google.com/store/apps/details?id=es.gob.radarcovid) |

If your project/country is not yet listed but uses the DP3T-SDK feel free to send a pull-request to add it to the [README](README).

## License
This project is licensed under the terms of the MPL 2 license. See the [LICENSE](LICENSE) file.
4 changes: 2 additions & 2 deletions calibration-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ ext.readProperty = { paramName ->
}

android {
compileSdkVersion 29
compileSdkVersion 30
buildToolsVersion "29.0.3"

defaultConfig {
applicationId "org.dpppt.android.calibration"
minSdkVersion 23
targetSdkVersion 29
targetSdkVersion 30
versionCode 2
versionName "0.2"

Expand Down
2 changes: 1 addition & 1 deletion calibration-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
Expand Down
4 changes: 2 additions & 2 deletions calibration-app/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
# SPDX-License-Identifier: MPL-2.0
#

#Mon Apr 06 09:12:35 CEST 2020
#Wed Sep 09 14:40:57 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
2 changes: 1 addition & 1 deletion dp3t-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
}
Expand Down
4 changes: 2 additions & 2 deletions dp3t-sdk/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Thu Mar 26 09:44:37 CET 2020
#Wed Sep 09 14:40:57 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
30 changes: 18 additions & 12 deletions dp3t-sdk/sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ plugins {
}

android {
compileSdkVersion 29
compileSdkVersion 30

defaultConfig {
minSdkVersion 23
targetSdkVersion 29
versionCode 104
versionName "1.0.4"
targetSdkVersion 30
versionCode 105
versionName "1.0.5"
testInstrumentationRunnerArgument 'androidx.benchmark.suppressErrors', 'EMULATOR,LOW-BATTERY,ACTIVITY-MISSING,DEBUGGABLE,UNLOCKED,UNSUSTAINED-ACTIVITY-MISSING'
testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"

Expand Down Expand Up @@ -65,29 +65,34 @@ afterEvaluate {
from components.productionRelease
groupId 'org.dpppt'
artifactId 'dp3t-sdk-android'
version android.defaultConfig.versionName
version android.defaultConfig.versionName + readPropertyWithDefault('bintrayVersionSuffix', '')
artifact androidSourcesJar
}
"sdkCalibration"(MavenPublication) {
from components.calibrationRelease
groupId 'org.dpppt'
artifactId 'dp3t-sdk-android'
version android.defaultConfig.versionName + "-calibration"
version android.defaultConfig.versionName + readPropertyWithDefault('bintrayVersionSuffix', '') + "-calibration"
artifact androidSourcesJar
}
}
}
}

ext.readProperty = { paramName ->
ext.readProperty = { paramName -> readPropertyWithDefault(paramName, null) }
ext.readPropertyWithDefault = { paramName, defaultValue ->
if (project.hasProperty(paramName)) {
return project.getProperties().get(paramName)
} else {
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}
return properties.getProperty(paramName)
if (properties.getProperty(paramName) != null) {
return properties.getProperty(paramName)
} else {
return defaultValue
}
}
}

Expand All @@ -114,7 +119,8 @@ sonarqube {
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
compileOnly fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
androidTestImplementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])

implementation 'androidx.core:core:1.2.0'
implementation 'androidx.security:security-crypto:1.0.0-rc01'
Expand All @@ -123,9 +129,9 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'

implementation 'io.jsonwebtoken:jjwt-api:0.11.1'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.1'
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.1') {
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.2') {
exclude group: 'org.json', module: 'json'
}
implementation 'org.bouncycastle:bcprov-jdk15on:1.65'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2020 Ubique Innovation AG <https://www.ubique.ch>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/
package org.dpppt.android.sdk.internal.backend;

import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;

import java.io.IOException;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;

import org.dpppt.android.sdk.backend.SignatureException;
import org.dpppt.android.sdk.internal.logger.LogLevel;
import org.dpppt.android.sdk.internal.logger.Logger;
import org.dpppt.android.sdk.internal.util.Base64Util;
import org.dpppt.android.sdk.models.DayDate;
import org.dpppt.android.sdk.util.SignatureUtil;
import org.junit.Before;
import org.junit.Test;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;

import static org.dpppt.android.sdk.util.SignatureUtil.JWS_CLAIM_CONTENT_HASH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

public class SignatureVerificationInterceptorTest {

Context context;
MockWebServer server;
BackendBucketRepository bucketRepository;
KeyPair keyPair;

@Before
public void setup() {
context = InstrumentationRegistry.getInstrumentation().getContext();

Logger.init(context, LogLevel.DEBUG);

ProxyConfig.DISABLE_SYSTEM_PROXY = true;

server = new MockWebServer();
keyPair = Keys.keyPairFor(SignatureAlgorithm.ES256);

bucketRepository = new BackendBucketRepository(context, server.url("/bucket/").toString(), keyPair.getPublic());
}

private String getJwtForContent(String content) {
HashMap<String, Object> claims = new HashMap<>();
try {
MessageDigest digest = MessageDigest.getInstance(SignatureUtil.HASH_ALGO);
claims.put(JWS_CLAIM_CONTENT_HASH, Base64Util.toBase64(digest.digest(content.getBytes())));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return Jwts.builder().addClaims(claims).signWith(keyPair.getPrivate()).compact();
}

@Test
public void testValidSignature() throws IOException, StatusCodeException {
String responseString = "someRandomContent";
server.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) {

return new MockResponse()
.setResponseCode(200)
.setBody(responseString)
.addHeader(SignatureUtil.HTTP_HEADER_JWS, getJwtForContent(responseString));
}
});
String response = bucketRepository.getGaenExposees(new DayDate(), null).body().string();
assertEquals(responseString, response);
}

@Test
public void testInvalidSignature() throws IOException, StatusCodeException {
String responseString = "someRandomContent";
server.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) {
return new MockResponse()
.setResponseCode(200)
.setBody(responseString)
.addHeader(SignatureUtil.HTTP_HEADER_JWS, getJwtForContent("differentContent"));
}
});
try {
bucketRepository.getGaenExposees(new DayDate(), null).body().string();
fail();
} catch (SignatureException e) {
assertEquals("Signature mismatch", e.getMessage());
}
}

@Test
public void testInvalidJwt() throws IOException, StatusCodeException {
String responseString = "someRandomContent";
server.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) {
return new MockResponse()
.setResponseCode(200)
.setBody(responseString)
.addHeader(SignatureUtil.HTTP_HEADER_JWS,
"eyJhbGciOiJFUzI1NiJ9.eyJjb250ZW50LWhhc2giOiJsTzd3TDBkOFl5MFBSaU" +
"w5NGhUa2txMkRXNUxXVjlPNi9zRWNZVDJHZ2t3PSIsImhhc2gtYWxnIjoic2hhLTI1Ni" +
"IsImlzcyI6ImRwM3QiLCJpYXQiOjE1ODgwODk2MDAsImV4cCI6MTU4OTkwNDAwMCwiYm" +
"F0Y2gtcmVsZWFzZS10aW1lIjoiMTU4ODA4OTYwMDAwMCJ9.1uiVGBOWqD8jLKm0_EOmN" +
"MMgHr4FQOsD1ci4iWR1QMitg_MPgtbuggedbuggedbuggedbuggedbuggedbugged");
}
});
try {
bucketRepository.getGaenExposees(new DayDate(), null).body().string();
fail();
} catch (SignatureException e) {
assertEquals("JWT signature does not match locally computed signature. " +
"JWT validity cannot be asserted and should not be trusted.", e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2020 Ubique Innovation AG <https://www.ubique.ch>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package org.dpppt.android.sdk.internal.nearby;

import android.content.Context;
import android.os.Build;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import org.dpppt.android.sdk.internal.ErrorHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

@RunWith(AndroidJUnit4.class)
public class LocationLessScanningTest {

private Context context;

@Before
public void setup() {
context = InstrumentationRegistry.getInstrumentation().getContext();
}

@Test
public void checkLocationLessScanningOnAndroidR(){
assertEquals(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R, ErrorHelper.deviceSupportsLocationlessScanning(context));
}
}
11 changes: 7 additions & 4 deletions dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/DP3T.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ private static void executeInit(Context context, AppConfigManager appConfigManag
new BluetoothStateBroadcastReceiver(),
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
);
context.registerReceiver(
new LocationServiceBroadcastReceiver(),
new IntentFilter(LocationManager.MODE_CHANGED_ACTION)
);
if (!ErrorHelper.deviceSupportsLocationlessScanning(context)) {
context.registerReceiver(
new LocationServiceBroadcastReceiver(),
new IntentFilter(LocationManager.MODE_CHANGED_ACTION)
);
}
context.registerReceiver(
new BatteryOptimizationBroadcastReceiver(),
new IntentFilter(BatteryOptimizationBroadcastReceiver.ACTION_POWER_SAVE_WHITELIST_CHANGED)
Expand Down Expand Up @@ -205,6 +207,7 @@ public static void sync(Context context) {

public static TracingStatus getStatus(Context context) {
checkInit();
GaenStateHelper.invalidateGaenEnabled(context);
AppConfigManager appConfigManager = AppConfigManager.getInstance(context);
Collection<TracingStatus.ErrorState> errorStates = ErrorHelper.checkTracingErrorStatus(context, appConfigManager);
InfectionStatus infectionStatus;
Expand Down
Loading

0 comments on commit e4d7188

Please sign in to comment.