From 72bca7eddcb46da60d7151d45bbb1c246b2f7f10 Mon Sep 17 00:00:00 2001 From: Simon Laalo Date: Thu, 7 Mar 2019 17:18:05 -0800 Subject: [PATCH 1/5] Incrementing to kotlin 1.3.21 Incrementing to gradle 3.3.2 Incrementing build version names and codes Incrementing compile SDK to 28 Incrementing buildTools to 28.0.3 Incrementing targetSdk to 28 Incrementing appCompat to 28.0.0 Adding local broadcast of pinning failures Adding examples of PinningFailureReportBroadcastReceiver Adding test for local broadcast of pinning failures --- README.md | 16 +++++ app/build.gradle | 3 - .../trustkit/demoapp/DemoMainActivity.java | 20 +++++- ...PinningFailureReportBroadcastReceiver.java | 26 +++++++ build.gradle | 24 +++---- demoappkotlin/build.gradle | 8 ++- demoappkotlin/src/main/AndroidManifest.xml | 3 +- .../demoappkotlin/DemoMainActivity.kt | 18 ++++- .../PinningFailureReportBroadcastReceiver.kt | 24 +++++++ gradle/wrapper/gradle-wrapper.properties | 4 +- trustkit/build.gradle | 1 + .../reporting/BackgroundReporterTest.java | 70 ++++++++++++++----- .../reporting/TestableBackgroundReporter.java | 5 +- .../android/trustkit/TrustKit.java | 8 ++- .../reporting/BackgroundReporter.java | 23 +++++- 15 files changed, 209 insertions(+), 44 deletions(-) create mode 100644 app/src/main/java/com/datatheorem/android/trustkit/demoapp/PinningFailureReportBroadcastReceiver.java create mode 100644 demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/PinningFailureReportBroadcastReceiver.kt diff --git a/README.md b/README.md index 83f4602..cc44845 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,11 @@ protected void onCreate(Bundle savedInstanceState) { URL url = new URL("https://www.datatheorem.com"); String serverHostname = url.getHost(); + + //Optionally add a local broadcast receiver to receive PinningFailureReports + PinningValidationReportTestBroadcastReceiver receiver = new PinningValidationReportTestBroadcastReceiver(); + LocalBroadcastManager.getInstance(context) + .registerReceiver(receiver, new IntentFilter(BackgroundReporter.REPORT_VALIDATION_EVENT)); // HttpsUrlConnection HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); @@ -127,10 +132,21 @@ protected void onCreate(Bundle savedInstanceState) { TrustKit.getInstance().getTrustManager(serverHostname)) .build(); } + +class PinningFailureReportBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + PinningFailureReport report = (PinningFailureReport) intent.getSerializableExtra(BackgroundReporter.EXTRA_REPORT); + } +} ``` Once TrustKit has been initialized and the client or connection's `SSLSocketFactory` has been set, it will verify the server's certificate chain against the configured pinning policy whenever an HTTPS connection is initiated. If a report URI has been configured, the App will also send reports to the specified URI whenever a pin validation failure occurred. +You can also create and register local broadcast receivers to receive the same certificate pinning error reports that would be sent to the report_uris. + + Limitations ---------- diff --git a/app/build.gradle b/app/build.gradle index 784427b..2ef90ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,7 +25,4 @@ dependencies { implementation project(':trustkit') implementation "com.android.support:appcompat-v7:$rootProject.libVersions.android.appCompat" implementation "com.android.support:design:$rootProject.libVersions.android.appCompat" - - androidTestApi "junit:junit:$rootProject.libVersions.junit" - } diff --git a/app/src/main/java/com/datatheorem/android/trustkit/demoapp/DemoMainActivity.java b/app/src/main/java/com/datatheorem/android/trustkit/demoapp/DemoMainActivity.java index 1dbd00d..5ad5937 100644 --- a/app/src/main/java/com/datatheorem/android/trustkit/demoapp/DemoMainActivity.java +++ b/app/src/main/java/com/datatheorem/android/trustkit/demoapp/DemoMainActivity.java @@ -1,24 +1,31 @@ package com.datatheorem.android.trustkit.demoapp; +import android.content.IntentFilter; import android.os.AsyncTask; import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; + import com.datatheorem.android.trustkit.TrustKit; +import com.datatheorem.android.trustkit.reporting.BackgroundReporter; + import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; + import javax.net.ssl.HttpsURLConnection; public class DemoMainActivity extends AppCompatActivity { - private static final String DEBUG_TAG = "TrustKit-Demo"; + protected static final String DEBUG_TAG = "TrustKit-Demo"; + private static final PinningFailureReportBroadcastReceiver pinningFailureReportBroadcastReceiver = new PinningFailureReportBroadcastReceiver(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -38,6 +45,17 @@ protected void onCreate(Bundle savedInstanceState) { new DownloadWebpageTask().execute("https://www.google.com"); textView.setText("Connection results are in the logs"); + + IntentFilter intentFilter = new IntentFilter(BackgroundReporter.REPORT_VALIDATION_EVENT); + LocalBroadcastManager.getInstance(getApplicationContext()) + .registerReceiver(pinningFailureReportBroadcastReceiver,intentFilter); + } + + @Override + protected void onDestroy() { + LocalBroadcastManager.getInstance(getApplicationContext()) + .unregisterReceiver(pinningFailureReportBroadcastReceiver); + super.onDestroy(); } private class DownloadWebpageTask extends AsyncTask { diff --git a/app/src/main/java/com/datatheorem/android/trustkit/demoapp/PinningFailureReportBroadcastReceiver.java b/app/src/main/java/com/datatheorem/android/trustkit/demoapp/PinningFailureReportBroadcastReceiver.java new file mode 100644 index 0000000..362976e --- /dev/null +++ b/app/src/main/java/com/datatheorem/android/trustkit/demoapp/PinningFailureReportBroadcastReceiver.java @@ -0,0 +1,26 @@ +package com.datatheorem.android.trustkit.demoapp; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import com.datatheorem.android.trustkit.reporting.BackgroundReporter; + +import java.io.Serializable; + +/** + * Class that provides an example broadcast receiver + * + *

+ * Applications using TrustKit can listen for local broadcasts and receive the same report that + * would be sent to the report_url. + *

+ **/ +class PinningFailureReportBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Serializable result = intent.getSerializableExtra(BackgroundReporter.EXTRA_REPORT); + Log.i(DemoMainActivity.DEBUG_TAG, result.toString()); + } +} diff --git a/build.gradle b/build.gradle index a1cd784..03b6500 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.2.50' + ext.kotlin_version = '1.3.21' repositories { jcenter() google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' // NOTE: Do not place your application dependencies here; they belong @@ -27,22 +27,22 @@ allprojects { ext{ - trustkitVersionCode = 6 - trustkitVersionName = "1.1.0" + trustkitVersionCode = 7 + trustkitVersionName = "1.1.1" - demoAppTrustKitVersionCode = 1 - demoAppTrustKitVersionName = "1.0" + demoAppTrustKitVersionCode = 2 + demoAppTrustKitVersionName = "1.1" - demoAppKotlinTrustKitVersionCode = 1 - demoAppKotlinTrustKitVersionName = "1.0" + demoAppKotlinTrustKitVersionCode = 2 + demoAppKotlinTrustKitVersionName = "1.1" javaSourceCompatibilty = '1.6' toolVersions = [ android : [ - compileSdk : 27, + compileSdk : 28, gradlePlugin : '2.1.0', - buildTools : '27.0.3', + buildTools : '28.0.3', minSdk : 15, - targetSdk: 27 + targetSdk: 28 ] ] @@ -53,7 +53,7 @@ ext{ ], dexmaker : '1.4', android : [ - appCompat : '27.1.1', + appCompat : '28.0.0', testRunner: '0.5' ], testing: [ diff --git a/demoappkotlin/build.gradle b/demoappkotlin/build.gradle index 7518feb..d9c60a1 100644 --- a/demoappkotlin/build.gradle +++ b/demoappkotlin/build.gradle @@ -31,9 +31,13 @@ dependencies { implementation "com.android.support:appcompat-v7:$libVersions.android.appCompat" implementation "com.android.support:design:$libVersions.android.appCompat" - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation project(path: ':trustkit') + + androidTestImplementation "junit:junit:$rootProject.libVersions.junit" + androidTestImplementation "com.android.support.test:runner:$rootProject.libVersions.android.testRunner" - compile project(path: ':trustkit') } repositories { mavenCentral() diff --git a/demoappkotlin/src/main/AndroidManifest.xml b/demoappkotlin/src/main/AndroidManifest.xml index ebd8583..ec20140 100644 --- a/demoappkotlin/src/main/AndroidManifest.xml +++ b/demoappkotlin/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - :w + + diff --git a/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/DemoMainActivity.kt b/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/DemoMainActivity.kt index 10d93ed..b760e01 100644 --- a/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/DemoMainActivity.kt +++ b/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/DemoMainActivity.kt @@ -1,7 +1,9 @@ package com.datatheorem.android.trustkit.demoappkotlin +import android.content.IntentFilter import android.os.AsyncTask import android.os.Bundle +import android.support.v4.content.LocalBroadcastManager import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar import android.util.Log @@ -10,6 +12,7 @@ import android.view.MenuItem import android.view.View import android.widget.TextView import com.datatheorem.android.trustkit.TrustKit +import com.datatheorem.android.trustkit.reporting.BackgroundReporter import java.io.IOException import java.net.MalformedURLException import java.net.URL @@ -17,6 +20,7 @@ import javax.net.ssl.HttpsURLConnection class DemoMainActivity : AppCompatActivity() { + private lateinit var pinningFailureReportBroadcastReceiver: PinningFailureReportBroadcastReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -35,6 +39,18 @@ class DemoMainActivity : AppCompatActivity() { DownloadWebpageTask().execute("https://www.google.com") textView.text = "Connection results are in the logs" + + // Adding a local broadcast receiver to listen for validation report events + pinningFailureReportBroadcastReceiver = PinningFailureReportBroadcastReceiver() + val intentFilter = IntentFilter(BackgroundReporter.REPORT_VALIDATION_EVENT) + LocalBroadcastManager.getInstance(this.applicationContext) + .registerReceiver(pinningFailureReportBroadcastReceiver,intentFilter) + } + + override fun onDestroy() { + LocalBroadcastManager.getInstance(this.applicationContext) + .unregisterReceiver(pinningFailureReportBroadcastReceiver) + super.onDestroy() } private inner class DownloadWebpageTask : AsyncTask() { @@ -83,7 +99,7 @@ class DemoMainActivity : AppCompatActivity() { companion object { - private const val DEBUG_TAG = "TrustKit-Demo" + internal const val DEBUG_TAG = "TrustKit-Demo" } } diff --git a/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/PinningFailureReportBroadcastReceiver.kt b/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/PinningFailureReportBroadcastReceiver.kt new file mode 100644 index 0000000..acbab09 --- /dev/null +++ b/demoappkotlin/src/main/java/com/datatheorem/android/trustkit/demoappkotlin/PinningFailureReportBroadcastReceiver.kt @@ -0,0 +1,24 @@ +package com.datatheorem.android.trustkit.demoappkotlin + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import com.datatheorem.android.trustkit.reporting.BackgroundReporter + +/** + * Class that provides an example broadcast receiver + * + *

+ * Applications using TrustKit can listen for local broadcasts and receive the same report that + * would be sent to the report_url. + *

+ **/ +class PinningFailureReportBroadcastReceiver : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + val result = intent.getSerializableExtra(BackgroundReporter.EXTRA_REPORT) + Log.i(DemoMainActivity.DEBUG_TAG, result.toString()) + } + +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index af0241d..523dc90 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Aug 10 17:35:22 CEST 2018 +#Wed Mar 06 15:49:41 PST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/trustkit/build.gradle b/trustkit/build.gradle index 8d02f3c..b34c461 100644 --- a/trustkit/build.gradle +++ b/trustkit/build.gradle @@ -33,6 +33,7 @@ dependencies { androidTestImplementation "com.android.support.test:runner:$rootProject.libVersions.android.testRunner" androidTestImplementation "com.android.support.test:rules:$rootProject.libVersions.android.testRunner" androidTestImplementation "org.mockito:mockito-core:$rootProject.libVersions.mockito.android" + androidTestImplementation "org.awaitility:awaitility:3.1.6" androidTestImplementation "com.crittercism.dexmaker:dexmaker:$rootProject.libVersions.dexmaker" androidTestImplementation "com.crittercism.dexmaker:dexmaker-dx:$rootProject.libVersions.dexmaker" androidTestImplementation "com.crittercism.dexmaker:dexmaker-mockito:$rootProject.libVersions.dexmaker" diff --git a/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/BackgroundReporterTest.java b/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/BackgroundReporterTest.java index 3acf6cf..13c138b 100644 --- a/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/BackgroundReporterTest.java +++ b/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/BackgroundReporterTest.java @@ -1,25 +1,20 @@ package com.datatheorem.android.trustkit.reporting; -import static com.datatheorem.android.trustkit.CertificateUtils.testCertChain; -import static com.datatheorem.android.trustkit.CertificateUtils.testCertChainPem; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.Build; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; +import android.support.v4.content.LocalBroadcastManager; + import com.datatheorem.android.trustkit.TestableTrustKit; import com.datatheorem.android.trustkit.config.DomainPinningPolicy; import com.datatheorem.android.trustkit.pinning.PinningValidationResult; import com.datatheorem.android.trustkit.utils.VendorIdentifier; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashSet; + +import org.awaitility.Awaitility; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -29,6 +24,23 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.datatheorem.android.trustkit.CertificateUtils.testCertChain; +import static com.datatheorem.android.trustkit.CertificateUtils.testCertChainPem; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + @RunWith(AndroidJUnit4.class) public class BackgroundReporterTest { @@ -44,7 +56,7 @@ public void testPinValidationFailed() throws MalformedURLException, JSONExceptio // TrustKit does not do anything for API level < 17 hence there is no reporting return; } - + Context context = InstrumentationRegistry.getContext(); // Initialize TrustKit String serverHostname = "mail.google.com"; final DomainPinningPolicy domainPolicy = new DomainPinningPolicy.Builder() @@ -60,9 +72,14 @@ public void testPinValidationFailed() throws MalformedURLException, JSONExceptio .setReportUris(new HashSet() {{ add("https://overmind.datatheorem.com"); }}) .build(); - TestableBackgroundReporter reporter = new TestableBackgroundReporter("com.unit.tests", + final PinningValidationReportTestBroadcastReceiver receiver = new PinningValidationReportTestBroadcastReceiver(); + LocalBroadcastManager.getInstance(context) + .registerReceiver(receiver, new IntentFilter(BackgroundReporter.REPORT_VALIDATION_EVENT)); + + TestableBackgroundReporter reporter = new TestableBackgroundReporter( context, + "com.unit.tests", "1.2", - VendorIdentifier.getOrCreate(InstrumentationRegistry.getContext())); + VendorIdentifier.getOrCreate(context)); TestableBackgroundReporter reporterSpy = Mockito.spy(reporter); // Call the method twice to also test the report rate limiter @@ -81,8 +98,17 @@ public void testPinValidationFailed() throws MalformedURLException, JSONExceptio eq(new HashSet() {{ add(new URL("https://overmind.datatheorem.com")); }} ) ); + validateSentReport(reportSent.getValue()); + + Awaitility.await().atMost(2, TimeUnit.SECONDS).untilTrue(receiver.broadcastReceived); + assertTrue(receiver.broadcastReceived.get()); + assertTrue(receiver.containedReport instanceof PinningFailureReport); + validateSentReport((PinningFailureReport) receiver.containedReport); + } + + private void validateSentReport(PinningFailureReport reportSent) throws JSONException { // Validate the content of the generated report - JSONObject reportSentJson = reportSent.getValue().toJson(); + JSONObject reportSentJson = reportSent.toJson(); assertEquals("com.unit.tests", reportSentJson.getString("app-bundle-id")); assertEquals("1.2", reportSentJson.getString("app-version")); assertEquals("ANDROID", reportSentJson.getString("app-platform")); @@ -123,7 +149,17 @@ public void testPinValidationFailed() throws MalformedURLException, JSONExceptio .contains("pin-sha256=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"")); assertTrue(pinsTestable .contains("pin-sha256=\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\"")); + } + private class PinningValidationReportTestBroadcastReceiver extends BroadcastReceiver{ + public AtomicBoolean broadcastReceived = new AtomicBoolean(false); + public Serializable containedReport; + + @Override + public void onReceive(Context context, Intent intent) { + broadcastReceived.set(true); + containedReport = intent.getSerializableExtra(BackgroundReporter.EXTRA_REPORT); + } } } diff --git a/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/TestableBackgroundReporter.java b/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/TestableBackgroundReporter.java index 073103f..639d231 100644 --- a/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/TestableBackgroundReporter.java +++ b/trustkit/src/androidTest/java/com/datatheorem/android/trustkit/reporting/TestableBackgroundReporter.java @@ -1,6 +1,7 @@ package com.datatheorem.android.trustkit.reporting; +import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.RequiresApi; import java.net.URL; @@ -9,8 +10,8 @@ @RequiresApi(api = 16) public class TestableBackgroundReporter extends BackgroundReporter { - public TestableBackgroundReporter(String appPackageName, String appVersion, String appVendorId){ - super(appPackageName, appVersion, appVendorId); + public TestableBackgroundReporter(Context context, String appPackageName, String appVersion, String appVendorId){ + super(context, appPackageName, appVersion, appVendorId); } @Override diff --git a/trustkit/src/main/java/com/datatheorem/android/trustkit/TrustKit.java b/trustkit/src/main/java/com/datatheorem/android/trustkit/TrustKit.java index 7319f2d..67bb212 100644 --- a/trustkit/src/main/java/com/datatheorem/android/trustkit/TrustKit.java +++ b/trustkit/src/main/java/com/datatheorem/android/trustkit/TrustKit.java @@ -6,12 +6,16 @@ import android.os.Build; import android.support.annotation.NonNull; import android.util.Printer; + import com.datatheorem.android.trustkit.config.ConfigurationException; import com.datatheorem.android.trustkit.config.TrustKitConfiguration; import com.datatheorem.android.trustkit.pinning.TrustManagerBuilder; import com.datatheorem.android.trustkit.reporting.BackgroundReporter; import com.datatheorem.android.trustkit.utils.TrustKitLog; import com.datatheorem.android.trustkit.utils.VendorIdentifier; + +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; @@ -19,11 +23,11 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Set; + import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import org.xmlpull.v1.XmlPullParserException; /** @@ -203,7 +207,7 @@ protected TrustKit(@NonNull Context context, } String appVendorId = VendorIdentifier.getOrCreate(context); - BackgroundReporter reporter = new BackgroundReporter(appPackageName, appVersion, + BackgroundReporter reporter = new BackgroundReporter(context, appPackageName, appVersion, appVendorId); // Initialize the trust manager builder diff --git a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/BackgroundReporter.java b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/BackgroundReporter.java index 8855dd8..04d5613 100644 --- a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/BackgroundReporter.java +++ b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/BackgroundReporter.java @@ -1,12 +1,17 @@ package com.datatheorem.android.trustkit.reporting; +import android.content.Context; +import android.content.Intent; import android.support.annotation.NonNull; import android.support.annotation.RequiresApi; +import android.support.v4.content.LocalBroadcastManager; import android.util.Base64; + import com.datatheorem.android.trustkit.config.DomainPinningPolicy; import com.datatheorem.android.trustkit.pinning.PinningValidationResult; import com.datatheorem.android.trustkit.utils.TrustKitLog; + import java.net.URL; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; @@ -17,17 +22,22 @@ public class BackgroundReporter { + public static final String REPORT_VALIDATION_EVENT = "com.datatheorem.android.trustkit.reporting.BackgroundReporter:REPORT_VALIDATION_EVENT"; + public static final String EXTRA_REPORT = "Report"; // App meta-data to be sent with the reports private final String appPackageName; private final String appVersion; private final String appVendorId; + private final Context context; - public BackgroundReporter(@NonNull String appPackageName, @NonNull String appVersion, + public BackgroundReporter(@NonNull Context context, @NonNull String appPackageName, @NonNull String appVersion, @NonNull String appVendorId) { + this.context = context; this.appPackageName = appPackageName; this.appVersion = appVersion; this.appVendorId = appVendorId; + } private static String certificateToPem(X509Certificate certificate) { @@ -85,6 +95,7 @@ validatedCertificateChainAsPem, new Date(System.currentTimeMillis()), // If a similar report hasn't been sent recently, send it now if (!(ReportRateLimiter.shouldRateLimit(report))) { sendReport(report, serverConfig.getReportUris()); + broadcastReport(report); } else { TrustKitLog.i("Report for " + serverHostname + " was not sent due to rate-limiting"); } @@ -101,5 +112,15 @@ protected void sendReport(@NonNull PinningFailureReport report, } // Call the task new BackgroundReporterTask().execute(taskParameters.toArray()); + } + + protected void broadcastReport(@NonNull PinningFailureReport report){ + Intent intent = new Intent(REPORT_VALIDATION_EVENT); + intent.putExtra(EXTRA_REPORT, report); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + + + + } } From 407e30996877e8fcda7020dba9a1b73b49c0157c Mon Sep 17 00:00:00 2001 From: Simon Laalo Date: Thu, 7 Mar 2019 18:11:10 -0800 Subject: [PATCH 2/5] Making PinningFailureReport public for use by calling apps --- build.gradle | 4 ++-- .../trustkit/reporting/PinningFailureReport.java | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 03b6500..8cdcad8 100644 --- a/build.gradle +++ b/build.gradle @@ -27,8 +27,8 @@ allprojects { ext{ - trustkitVersionCode = 7 - trustkitVersionName = "1.1.1" + trustkitVersionCode = 8 + trustkitVersionName = "1.1.2" demoAppTrustKitVersionCode = 2 demoAppTrustKitVersionName = "1.1" diff --git a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java index ba13d58..3b848c1 100644 --- a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java +++ b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java @@ -2,21 +2,24 @@ import android.support.annotation.NonNull; import android.text.format.DateFormat; + import com.datatheorem.android.trustkit.BuildConfig; import com.datatheorem.android.trustkit.config.PublicKeyPin; import com.datatheorem.android.trustkit.pinning.PinningValidationResult; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.Serializable; import java.util.Date; import java.util.List; import java.util.Set; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; /** * A pinning validation failure report. */ -class PinningFailureReport implements Serializable { +public class PinningFailureReport implements Serializable { // Fields specific to TrustKit reports private static final String APP_PLATFORM = "ANDROID"; private static final String trustKitVersion = BuildConfig.VERSION_NAME; From 0e0a94328a448ec129e3553032201d0dd9cbde9d Mon Sep 17 00:00:00 2001 From: Simon Laalo Date: Thu, 7 Mar 2019 18:21:29 -0800 Subject: [PATCH 3/5] Making PinningFailureReport public for use by calling apps --- .../android/trustkit/reporting/PinningFailureReport.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java index 3b848c1..111a237 100644 --- a/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java +++ b/trustkit/src/main/java/com/datatheorem/android/trustkit/reporting/PinningFailureReport.java @@ -113,12 +113,12 @@ public String toString() { } @NonNull - String getNotedHostname() { + public String getNotedHostname() { return notedHostname; } @NonNull - String getServerHostname() { + public String getServerHostname() { return serverHostname; } @@ -128,7 +128,7 @@ List getValidatedCertificateChainAsPem() { } @NonNull - PinningValidationResult getValidationResult() { + public PinningValidationResult getValidationResult() { return validationResult; } From 59fc3adca08ea07823471657639b0e9e8228e7f4 Mon Sep 17 00:00:00 2001 From: Simon Laalo Date: Thu, 7 Mar 2019 18:28:48 -0800 Subject: [PATCH 4/5] no message --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8cdcad8..03b6500 100644 --- a/build.gradle +++ b/build.gradle @@ -27,8 +27,8 @@ allprojects { ext{ - trustkitVersionCode = 8 - trustkitVersionName = "1.1.2" + trustkitVersionCode = 7 + trustkitVersionName = "1.1.1" demoAppTrustKitVersionCode = 2 demoAppTrustKitVersionName = "1.1" From 561bc9fd44958834ecf2fcd56f89a58b77ceb874 Mon Sep 17 00:00:00 2001 From: Simon Laalo Date: Mon, 11 Mar 2019 15:19:49 -0700 Subject: [PATCH 5/5] adding proguard rules for private static members used in local broadcast intents --- trustkit/proguard-rules.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trustkit/proguard-rules.pro b/trustkit/proguard-rules.pro index cade0cf..d36a045 100644 --- a/trustkit/proguard-rules.pro +++ b/trustkit/proguard-rules.pro @@ -15,3 +15,7 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} + +-keep class com.datatheorem.android.trustkit.reporting.BackgroundReporter { + public static *; +} \ No newline at end of file