mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-12-03 16:27:26 +00:00
EN: Don't allow apps to turn off EN that didn't turn it on before
This commit is contained in:
parent
9b91bf63c6
commit
0cd028af0e
6 changed files with 94 additions and 30 deletions
|
@ -6,7 +6,7 @@
|
|||
buildscript {
|
||||
ext.nlpVersion = '2.0-alpha5'
|
||||
ext.remoteDroidGuardVersion = '0.1.2'
|
||||
ext.safeParcelVersion = '1.6.0'
|
||||
ext.safeParcelVersion = '1.7.0'
|
||||
ext.wearableVersion = '0.1.1'
|
||||
|
||||
ext.kotlinVersion = '1.4.10'
|
||||
|
|
|
@ -41,13 +41,13 @@ import java.util.Map;
|
|||
*/
|
||||
@PublicApi
|
||||
public class DailySummariesConfig extends AutoSafeParcelable {
|
||||
@Field(1)
|
||||
@Field(value = 1, useDirectList = true)
|
||||
private List<Double> reportTypeWeights;
|
||||
@Field(2)
|
||||
@Field(value = 2, useDirectList = true)
|
||||
private List<Double> infectiousnessWeights;
|
||||
@Field(3)
|
||||
@Field(value = 3, useDirectList = true)
|
||||
private List<Integer> attenuationBucketThresholdDb;
|
||||
@Field(4)
|
||||
@Field(value = 4, useDirectList = true)
|
||||
private List<Double> attenuationBucketWeights;
|
||||
@Field(5)
|
||||
private int daysSinceExposureThreshold;
|
||||
|
|
|
@ -11,6 +11,7 @@ package com.google.android.gms.nearby.exposurenotification;
|
|||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.safeparcel.AutoSafeParcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -21,8 +22,8 @@ import java.util.Map;
|
|||
*/
|
||||
@PublicApi
|
||||
public class DiagnosisKeysDataMapping extends AutoSafeParcelable {
|
||||
@Field(1)
|
||||
private List<Integer> daysSinceOnsetToInfectiousness;
|
||||
@Field(value = 1, useDirectList = true)
|
||||
private List<Integer> daysSinceOnsetToInfectiousness = new ArrayList<>();
|
||||
@Field(2)
|
||||
@ReportType
|
||||
private int reportTypeWhenMissing;
|
||||
|
@ -82,7 +83,7 @@ public class DiagnosisKeysDataMapping extends AutoSafeParcelable {
|
|||
if (infectiousnessWhenDaysSinceOnsetMissing == null)
|
||||
throw new IllegalStateException("Must set infectiousnessWhenDaysSinceOnsetMissing");
|
||||
DiagnosisKeysDataMapping mapping = new DiagnosisKeysDataMapping();
|
||||
mapping.daysSinceOnsetToInfectiousness = daysSinceOnsetToInfectiousness;
|
||||
mapping.daysSinceOnsetToInfectiousness = new ArrayList<>(daysSinceOnsetToInfectiousness);
|
||||
mapping.reportTypeWhenMissing = reportTypeWhenMissing;
|
||||
mapping.infectiousnessWhenDaysSinceOnsetMissing = infectiousnessWhenDaysSinceOnsetMissing;
|
||||
return mapping;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package org.microg.gms.nearby.exposurenotification
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.util.Log
|
||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
@ -45,7 +46,7 @@ fun getPeriodInDay(intervalNumber: Int) = intervalNumber - getDayRollingStartNum
|
|||
|
||||
val nextKeyMillis: Long
|
||||
get() {
|
||||
val currentWindowStart = currentIntervalNumber * ROLLING_WINDOW_LENGTH * 1000
|
||||
val currentWindowStart = currentIntervalNumber.toLong() * ROLLING_WINDOW_LENGTH * 1000
|
||||
val currentWindowEnd = currentWindowStart + ROLLING_WINDOW_LENGTH * 1000
|
||||
return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
|
|||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
||||
import kotlinx.coroutines.*
|
||||
import okio.ByteString
|
||||
import org.microg.gms.common.PackageUtils
|
||||
import java.io.File
|
||||
import java.lang.Runnable
|
||||
import java.nio.ByteBuffer
|
||||
|
@ -61,7 +62,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
db.execSQL("CREATE TABLE $TABLE_APP_PERMS(package TEXT NOT NULL, sig TEXT NOT NULL, perm TEXT NOT NULL, timestamp INTEGER NOT NULL);")
|
||||
}
|
||||
if (oldVersion < 5) {
|
||||
Log.d(TAG, "Creating tables for version >= 3")
|
||||
Log.d(TAG, "Creating tables for version >= 5")
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_TOKENS(tid INTEGER PRIMARY KEY, package TEXT NOT NULL, token TEXT NOT NULL, timestamp INTEGER NOT NULL, configuration BLOB, diagnosisKeysDataMap BLOB);")
|
||||
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS index_${TABLE_TOKENS}_package_token ON $TABLE_TOKENS(package, token);")
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_TEK_CHECK_SINGLE(tcsid INTEGER PRIMARY KEY, keyData BLOB NOT NULL, rollingStartNumber INTEGER NOT NULL, rollingPeriod INTEGER NOT NULL, matched INTEGER);")
|
||||
|
@ -76,6 +77,10 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
db.execSQL("CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE_MATCH}_tcfid ON $TABLE_TEK_CHECK_FILE_MATCH(tcfid);")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS index_${TABLE_TEK_CHECK_FILE_MATCH}_key ON $TABLE_TEK_CHECK_FILE_MATCH(keyData, rollingStartNumber, rollingPeriod);")
|
||||
}
|
||||
if (oldVersion < 9) {
|
||||
Log.d(TAG, "Creating tables for version >= 9")
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_APP(package TEXT NOT NULL, sig TEXT NOT NULL, PRIMARY KEY (package, sig));")
|
||||
}
|
||||
if (oldVersion in 5 until 7) {
|
||||
Log.d(TAG, "Altering tables for version >= 7")
|
||||
db.execSQL("ALTER TABLE $TABLE_TOKENS ADD COLUMN diagnosisKeysDataMap BLOB;")
|
||||
|
@ -97,6 +102,22 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
// Entries might be invalid due to previously missing support for new bluetooth AEM format
|
||||
db.execSQL("DELETE FROM $TABLE_TEK_CHECK_FILE WHERE tcfid NOT IN (SELECT tcfid FROM $TABLE_TEK_CHECK_FILE_MATCH);")
|
||||
}
|
||||
if (oldVersion in 1 until 9) {
|
||||
Log.d(TAG, "Migrating authorized apps from version < 9")
|
||||
val pm = context.packageManager
|
||||
db.query(true, TABLE_APP_LOG, arrayOf("package"), null, null, null, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val packageName = cursor.getString(0)
|
||||
val signatureDigest = PackageUtils.firstSignatureDigest(pm, packageName)
|
||||
if (signatureDigest != null) {
|
||||
db.insertWithOnConflict(TABLE_APP, "NULL", ContentValues().apply {
|
||||
put("package", packageName)
|
||||
put("sig", signatureDigest)
|
||||
}, CONFLICT_IGNORE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Finished database upgrade")
|
||||
}
|
||||
|
||||
|
@ -177,6 +198,21 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
}, null, null)
|
||||
}
|
||||
|
||||
fun authorizeApp(packageName: String?, signatureDigest: String? = PackageUtils.firstSignatureDigest(context, packageName)) = writableDatabase.run {
|
||||
if (packageName == null || signatureDigest == null) return@run
|
||||
insertWithOnConflict(TABLE_APP, "NULL", ContentValues().apply {
|
||||
put("package", packageName)
|
||||
put("sig", signatureDigest)
|
||||
}, CONFLICT_IGNORE)
|
||||
}
|
||||
|
||||
fun isAppAuthorized(packageName: String?, signatureDigest: String? = PackageUtils.firstSignatureDigest(context, packageName)): Boolean = readableDatabase.run {
|
||||
if (packageName == null || signatureDigest == null) return@run false
|
||||
query(TABLE_APP, arrayOf("package"), "package = ? AND sig = ?", arrayOf(packageName, signatureDigest), null, null, null).use { cursor ->
|
||||
return@use cursor.moveToNext()
|
||||
}
|
||||
}
|
||||
|
||||
fun noteAppAction(packageName: String, method: String, args: String? = null, timestamp: Long = Date().time) = writableDatabase.run {
|
||||
insert(TABLE_APP_LOG, "NULL", ContentValues().apply {
|
||||
put("package", packageName)
|
||||
|
@ -186,7 +222,6 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
private fun storeOwnKey(key: TemporaryExposureKey, database: SQLiteDatabase = writableDatabase) = database.run {
|
||||
insert(TABLE_TEK, "NULL", ContentValues().apply {
|
||||
put("keyData", key.keyData)
|
||||
|
@ -746,7 +781,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
private fun ensureTemporaryExposureKey(): TemporaryExposureKey = writableDatabase.let { database ->
|
||||
database.beginTransactionNonExclusive()
|
||||
try {
|
||||
var key = findOwnKeyAt(currentIntervalNumber.toInt(), database)
|
||||
var key = findOwnKeyAt(currentIntervalNumber, database)
|
||||
if (key == null) {
|
||||
key = generateCurrentDayTemporaryExposureKey()
|
||||
storeOwnKey(key, database)
|
||||
|
@ -760,12 +795,12 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
|
||||
val currentRpiId: UUID?
|
||||
get() {
|
||||
val key = findOwnKeyAt(currentIntervalNumber.toInt()) ?: return null
|
||||
val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber.toInt()))
|
||||
val key = findOwnKeyAt(currentIntervalNumber) ?: return null
|
||||
val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber))
|
||||
return UUID(buffer.long, buffer.long)
|
||||
}
|
||||
|
||||
fun generateCurrentPayload(metadata: ByteArray) = ensureTemporaryExposureKey().generatePayload(currentIntervalNumber.toInt(), metadata)
|
||||
fun generateCurrentPayload(metadata: ByteArray) = ensureTemporaryExposureKey().generatePayload(currentIntervalNumber, metadata)
|
||||
|
||||
override fun getWritableDatabase(): SQLiteDatabase {
|
||||
requirePrimary(this)
|
||||
|
@ -791,10 +826,11 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||
|
||||
companion object {
|
||||
private const val DB_NAME = "exposure.db"
|
||||
private const val DB_VERSION = 8
|
||||
private const val DB_VERSION = 9
|
||||
private const val DB_SIZE_TOO_LARGE = 256L * 1024 * 1024
|
||||
private const val MAX_DELETE_TIME = 5000L
|
||||
private const val TABLE_ADVERTISEMENTS = "advertisements"
|
||||
private const val TABLE_APP = "app"
|
||||
private const val TABLE_APP_LOG = "app_log"
|
||||
private const val TABLE_TEK = "tek"
|
||||
private const val TABLE_APP_PERMS = "app_perms"
|
||||
|
|
|
@ -101,15 +101,14 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
}
|
||||
|
||||
override fun start(params: StartParams) {
|
||||
if (ExposurePreferences(context).enabled) {
|
||||
params.callback.onResult(Status.SUCCESS)
|
||||
return
|
||||
}
|
||||
lifecycleScope.launchWhenStarted {
|
||||
val status = confirmPermission(CONFIRM_ACTION_START)
|
||||
if (status.isSuccess) {
|
||||
ExposurePreferences(context).enabled = true
|
||||
ExposureDatabase.with(context) { database -> database.noteAppAction(packageName, "start") }
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.authorizeApp(packageName)
|
||||
database.noteAppAction(packageName, "start")
|
||||
}
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(status)
|
||||
|
@ -121,9 +120,13 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
|
||||
override fun stop(params: StopParams) {
|
||||
lifecycleScope.launchWhenStarted {
|
||||
ExposurePreferences(context).enabled = false
|
||||
ExposureDatabase.with(context) { database ->
|
||||
database.noteAppAction(packageName, "stop")
|
||||
val isAuthorized = ExposureDatabase.with(context) { database ->
|
||||
database.isAppAuthorized(packageName).also {
|
||||
if (it) database.noteAppAction(packageName, "stop")
|
||||
}
|
||||
}
|
||||
if (isAuthorized) {
|
||||
ExposurePreferences(context).enabled = false
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS)
|
||||
|
@ -134,10 +137,17 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
}
|
||||
|
||||
override fun isEnabled(params: IsEnabledParams) {
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, ExposurePreferences(context).enabled)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
lifecycleScope.launchWhenStarted {
|
||||
val isAuthorized = ExposureDatabase.with(context) { database ->
|
||||
database.isAppAuthorized(packageName).also {
|
||||
if (it) database.noteAppAction(packageName, "isEnabled")
|
||||
}
|
||||
}
|
||||
try {
|
||||
params.callback.onResult(Status.SUCCESS, isAuthorized && ExposurePreferences(context).enabled)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Callback failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +156,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
val status = confirmPermission(CONFIRM_ACTION_KEYS)
|
||||
val response = when {
|
||||
status.isSuccess -> ExposureDatabase.with(context) { database ->
|
||||
database.authorizeApp(packageName)
|
||||
database.exportKeys()
|
||||
}
|
||||
else -> emptyList()
|
||||
|
@ -194,6 +205,11 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
?: ExposureConfiguration.ExposureConfigurationBuilder().build()
|
||||
|
||||
private suspend fun buildExposureSummary(token: String): ExposureSummary = ExposureDatabase.with(context) { database ->
|
||||
if (!database.isAppAuthorized(packageName)) {
|
||||
// Not providing summary if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
return@with ExposureSummary.ExposureSummaryBuilder().build()
|
||||
}
|
||||
val pair = database.loadConfiguration(packageName, token)
|
||||
val (configuration, exposures) = if (pair != null) {
|
||||
pair.second.orDefault() to database.findAllMeasuredExposures(pair.first).merge()
|
||||
|
@ -334,6 +350,12 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
put("request_keys_count", keys)
|
||||
}.toString())
|
||||
|
||||
if (!database.isAppAuthorized(packageName)) {
|
||||
// Not sending results via broadcast if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
return@with
|
||||
}
|
||||
|
||||
val exposureSummary = buildExposureSummary(token)
|
||||
|
||||
try {
|
||||
|
@ -381,11 +403,13 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
lifecycleScope.launchWhenStarted {
|
||||
ExposureDatabase.with(context) { database ->
|
||||
val pair = database.loadConfiguration(packageName, params.token)
|
||||
val response = if (pair != null) {
|
||||
val response = if (pair != null && database.isAppAuthorized(packageName)) {
|
||||
database.findAllMeasuredExposures(pair.first).merge().map {
|
||||
it.toExposureInformation(pair.second.orDefault())
|
||||
}
|
||||
} else {
|
||||
// Not providing information if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
|
@ -425,9 +449,11 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||
private suspend fun getExposureWindowsInternal(token: String = TOKEN_A): List<ExposureWindow> {
|
||||
val (exposures, mapping) = ExposureDatabase.with(context) { database ->
|
||||
val triple = database.loadConfiguration(packageName, token)
|
||||
if (triple != null) {
|
||||
if (triple != null && database.isAppAuthorized(packageName)) {
|
||||
database.findAllMeasuredExposures(triple.first).merge() to triple.third.orDefault()
|
||||
} else {
|
||||
// Not providing windows if app not authorized
|
||||
Log.d(TAG, "$packageName not yet authorized")
|
||||
emptyList<MergedExposure>() to DiagnosisKeysDataMapping()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue