-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Schedule chaff background task. * Obfuscate data for chaff request (iOS). * Set X-Chaff header. * Implement JS layer chaff request. * Implement chaff request for verification code endpoint. * Address validation warnings/errors. * Post correct notification for chaff request. * Added 24 hour check to chaff with random flip. * Work/gaen 790 chaff requests (#918) * GAEN-790 Chaff Requests Schedule the work on Application launch Add the correct EventSender function to trigger the ts code Remove reusable code for encoding to a separate object file Add the new worker that schedules the periodic work * GAEN-790 Chaff Requests Add a ChaffManager class to handle specific timing for firing requests. * GAEN-790 Chaff Remove the random z variable * GAEN-790 Chaff Requests Attach a react context initializer to trigger Chaff Add a Config class for the ChaffManager to handle some QA needs * Added react debug menu for Android only chaff fast request call. * Added Android check to debug menu. Co-authored-by: lundjrl <jrlbidamin@gmail.com> * GAEN-772 Chaff Update the build.yml file with a new NDK version * GAEN-772 Chaff Apply Kotlin Format * GAEN-772 Chaff Adding another maven url * GAEN-772 Chaff Reformat Java Files * GAEN-772 Chaff Updated NDK version in the gradle file * GAEN-772 Chaff More import format updates * GAEN-772 Chaff The formatter is not working correctly so I am manually adjusting per each error I get * GAEN-772 Chaff Import formatting * Removed unnecessary print statement. * Should fix ios action failing. * Added default case to fix Switch must be exhaustive error. * Fixing debug test post push actions fail. * Fixing debug test post push actions fail. * Fixing debug test post push actions fail. Co-authored-by: Matt Buckley <matt@smalldevshop.co> Co-authored-by: Kyle Wolff <kyle.a.wolff87@gmail.com>
- Loading branch information
1 parent
6ef9652
commit 8be3404
Showing
28 changed files
with
804 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
137 changes: 137 additions & 0 deletions
137
...pp/src/main/java/org/pathcheck/covidsafepaths/exposurenotifications/chaff/ChaffManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package org.pathcheck.covidsafepaths.exposurenotifications.chaff | ||
|
||
import android.content.Context | ||
import android.util.Log | ||
import androidx.annotation.VisibleForTesting | ||
import com.facebook.react.bridge.WritableArray | ||
import com.google.gson.Gson | ||
import com.google.gson.reflect.TypeToken | ||
import java.security.SecureRandom | ||
import java.util.concurrent.TimeUnit | ||
import org.pathcheck.covidsafepaths.exposurenotifications.dto.RNExposureKey | ||
import org.pathcheck.covidsafepaths.exposurenotifications.utils.TimeProvider | ||
import org.pathcheck.covidsafepaths.exposurenotifications.utils.TimeProviderImpl | ||
import org.pathcheck.covidsafepaths.exposurenotifications.utils.Util | ||
|
||
class ChaffManager private constructor( | ||
context: Context, | ||
private val timeProvider: TimeProvider, | ||
private val secureRandom: SecureRandom | ||
) { | ||
|
||
private val sharedPreferences = context.getSharedPreferences(CHAFF_SHARED_PREF, Context.MODE_PRIVATE) | ||
private val currentTimeMillis get() = timeProvider.currentTimeInMillis | ||
private val currentTimeInHours get() = TimeUnit.MILLISECONDS.toHours(currentTimeMillis) | ||
private val lastFiredEventInHours: Long | ||
get() { | ||
val previousFiredTime = sharedPreferences.getLong(REQUEST_FIRED, 0L) | ||
return TimeUnit.MILLISECONDS.toHours(previousFiredTime) | ||
} | ||
|
||
private var config: Config = Config() | ||
|
||
fun setConfiguration(config: Config) { | ||
this.config = config | ||
} | ||
|
||
fun shouldFire(): Boolean { | ||
if (config.makeProbability100Percent) { | ||
return true | ||
} | ||
|
||
return secureRandom.nextDouble() < EXECUTION_PROBABILITY && hasBeen24Hours() | ||
} | ||
|
||
fun save(chaffKeys: List<RNExposureKey>?) { | ||
saveTime() | ||
convertTemporaryKeysToJson(chaffKeys).also { json -> | ||
sharedPreferences | ||
.edit() | ||
.putString(CHAFF_JSON, json) | ||
.apply() | ||
} | ||
} | ||
|
||
fun getChaffKeys(): WritableArray? = convertToWriteableArray(getSavedRNExposureKeys()) | ||
|
||
@VisibleForTesting | ||
fun getSavedRNExposureKeys(): List<RNExposureKey>? { | ||
return sharedPreferences.getString(CHAFF_JSON, "").let { json -> | ||
|
||
if (json.isNullOrEmpty()) { | ||
return null | ||
} | ||
val gson = Gson() | ||
val listType = TypeToken.getParameterized(List::class.java, RNExposureKey::class.java).type | ||
gson.fromJson(json, listType) | ||
} | ||
} | ||
|
||
fun getRepeatWorkerIntervalInMinutes(): Long { | ||
return config.repeatIntervalInMinutes | ||
} | ||
|
||
private fun convertTemporaryKeysToJson(rnExposureKeys: List<RNExposureKey>?): String { | ||
val gson = Gson() | ||
return gson.toJson(rnExposureKeys).also { | ||
Log.d("Chaff Json Log", it) | ||
} | ||
} | ||
|
||
private fun saveTime() { | ||
sharedPreferences | ||
.edit() | ||
.putLong(REQUEST_FIRED, currentTimeMillis) | ||
.apply() | ||
} | ||
|
||
private fun hasBeen24Hours(): Boolean { | ||
return lastFiredEventInHours == 0L || | ||
currentTimeInHours - lastFiredEventInHours >= TWENTY_FOUR_HOURS | ||
} | ||
|
||
private fun convertToWriteableArray(exposureKeys: List<RNExposureKey>?): WritableArray? { | ||
return Util.convertListToWritableArray(exposureKeys) | ||
} | ||
|
||
companion object { | ||
private const val CHAFF_SHARED_PREF = "ChaffManagerSharedPref" | ||
private const val REQUEST_FIRED = "requestFired" | ||
private const val CHAFF_JSON = "chaffJson" | ||
private const val EXECUTION_PROBABILITY = 1.0 / 12.0 | ||
private const val TWENTY_FOUR_HOURS = 24 | ||
|
||
private var chaffManager: ChaffManager? = null | ||
|
||
@JvmStatic | ||
@JvmOverloads | ||
fun getInstance( | ||
context: Context, | ||
timeProvider: TimeProvider = TimeProviderImpl, | ||
secureRandom: SecureRandom = SecureRandom() | ||
): ChaffManager { | ||
return chaffManager ?: ChaffManager(context, timeProvider, secureRandom).also { | ||
chaffManager = it | ||
} | ||
} | ||
|
||
@JvmStatic | ||
@VisibleForTesting | ||
fun createChaffManager( | ||
context: Context, | ||
timeProvider: TimeProvider, | ||
secureRandom: SecureRandom | ||
) = ChaffManager(context, timeProvider, secureRandom) | ||
} | ||
|
||
data class Config( | ||
val repeatIntervalInMinutes: Long = FOUR_HOURS_IN_MINUTES, | ||
val makeProbability100Percent: Boolean = false | ||
) { | ||
|
||
companion object { | ||
const val FIFTEEN_MINUTES = 15L | ||
const val FOUR_HOURS_IN_MINUTES = 240L | ||
} | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
.../main/java/org/pathcheck/covidsafepaths/exposurenotifications/chaff/ChaffRequestWorker.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package org.pathcheck.covidsafepaths.exposurenotifications.chaff | ||
|
||
import android.content.Context | ||
import android.util.Log | ||
import androidx.work.BackoffPolicy | ||
import androidx.work.Constraints | ||
import androidx.work.ExistingPeriodicWorkPolicy | ||
import androidx.work.ListenableWorker | ||
import androidx.work.NetworkType | ||
import androidx.work.PeriodicWorkRequest | ||
import androidx.work.WorkManager | ||
import androidx.work.WorkerParameters | ||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey | ||
import com.google.common.util.concurrent.FluentFuture | ||
import com.google.common.util.concurrent.Futures | ||
import com.google.common.util.concurrent.ListenableFuture | ||
import java.util.concurrent.TimeUnit | ||
import org.pathcheck.covidsafepaths.MainApplication | ||
import org.pathcheck.covidsafepaths.bridge.EventSender | ||
import org.pathcheck.covidsafepaths.exposurenotifications.ExposureNotificationClientWrapper | ||
import org.pathcheck.covidsafepaths.exposurenotifications.common.AppExecutors | ||
import org.pathcheck.covidsafepaths.exposurenotifications.dto.RNExposureKey | ||
import org.pathcheck.covidsafepaths.helpers.DiagnosisKeyEncoding | ||
|
||
class ChaffRequestWorker( | ||
application: Context, | ||
workerParams: WorkerParameters | ||
) : ListenableWorker(application, workerParams) { | ||
|
||
companion object { | ||
private const val TAG = "ChaffRequests" | ||
|
||
@JvmStatic | ||
fun scheduleWork(context: Context) { | ||
val chaffManager = ChaffManager.getInstance(context) | ||
|
||
val constraints = Constraints.Builder() | ||
.setRequiredNetworkType(NetworkType.CONNECTED) | ||
.build() | ||
|
||
val request = PeriodicWorkRequest.Builder( | ||
ChaffRequestWorker::class.java, | ||
chaffManager.getRepeatWorkerIntervalInMinutes(), | ||
TimeUnit.MINUTES | ||
) | ||
.setConstraints(constraints) | ||
.setBackoffCriteria(BackoffPolicy.LINEAR, PeriodicWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) | ||
.build() | ||
|
||
WorkManager.getInstance(context) | ||
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) | ||
} | ||
} | ||
|
||
private val app = application as? MainApplication | ||
private val reactContext = app?.reactNativeHost?.reactInstanceManager?.currentReactContext | ||
private val chaffManager = ChaffManager.getInstance(application) | ||
|
||
override fun startWork(): ListenableFuture<Result> { | ||
val wrapper = ExposureNotificationClientWrapper.get(app) | ||
|
||
if (!chaffManager.shouldFire()) { | ||
return Futures.immediateFuture(Result.success()) | ||
} | ||
|
||
return FluentFuture.from(wrapper.requestPermissionToGetExposureKeys(reactContext)) | ||
.transform( | ||
{ exposureKeys -> | ||
if (exposureKeys != null) { | ||
chaffManager.save(encodeKeys(exposureKeys)) | ||
EventSender.sendChaffRequest(reactContext) | ||
Result.success() | ||
} else { | ||
Result.failure() | ||
} | ||
}, | ||
AppExecutors.getBackgroundExecutor() | ||
) | ||
.catching( | ||
Exception::class.java, | ||
{ exception -> | ||
Log.e( | ||
"ChaffRequestWorker", | ||
"Failure to update app state (tokens, etc) from exposure summary.", exception | ||
) | ||
Result.failure() | ||
}, | ||
AppExecutors.getLightweightExecutor() | ||
) | ||
} | ||
|
||
private fun encodeKeys(exposureKeys: List<TemporaryExposureKey>?): List<RNExposureKey>? { | ||
return exposureKeys?.run { | ||
DiagnosisKeyEncoding.encodeDiagnosisKeys(exposureKeys, true) | ||
} | ||
} | ||
} |
5 changes: 4 additions & 1 deletion
5
...p/src/main/java/org/pathcheck/covidsafepaths/exposurenotifications/dto/RNExposureKey.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.