mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-09-13 01:37:12 +02:00
EN: Allow exporting key of current day
This requires rotating the daily TEK when exporting
This commit is contained in:
parent
0e0ac35e51
commit
369c3d7557
@ -39,7 +39,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
tools:text="Your phonre needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app." />
|
tools:text="Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app." />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/grant_permission_view"
|
android:id="@+id/grant_permission_view"
|
||||||
|
@ -34,11 +34,14 @@ private const val AES_BLOCK_SIZE = 16
|
|||||||
|
|
||||||
private const val AEM_ALGORITHM = "AES/CTR/NoPadding"
|
private const val AEM_ALGORITHM = "AES/CTR/NoPadding"
|
||||||
|
|
||||||
val currentIntervalNumber: Long
|
val currentIntervalNumber: Int
|
||||||
get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toLong()
|
get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toInt()
|
||||||
|
|
||||||
val currentRollingStartNumber: Long
|
val currentDayRollingStartNumber: Int
|
||||||
get() = floor(currentIntervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD
|
get() = getDayRollingStartNumber(currentIntervalNumber)
|
||||||
|
|
||||||
|
fun getDayRollingStartNumber(intervalNumber: Int) = (floor(currentIntervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD).toInt()
|
||||||
|
fun getPeriodInDay(intervalNumber: Int) = intervalNumber - getDayRollingStartNumber(intervalNumber)
|
||||||
|
|
||||||
val nextKeyMillis: Long
|
val nextKeyMillis: Long
|
||||||
get() {
|
get() {
|
||||||
@ -47,18 +50,16 @@ val nextKeyMillis: Long
|
|||||||
return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)
|
return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TemporaryExposureKey.TemporaryExposureKeyBuilder.setCurrentRollingStartNumber(): TemporaryExposureKey.TemporaryExposureKeyBuilder =
|
fun generateTemporaryExposureKey(intervalNumber: Int): TemporaryExposureKey.TemporaryExposureKeyBuilder = TemporaryExposureKey.TemporaryExposureKeyBuilder().apply {
|
||||||
setRollingStartIntervalNumber(currentRollingStartNumber.toInt())
|
|
||||||
|
|
||||||
fun TemporaryExposureKey.TemporaryExposureKeyBuilder.generate(): TemporaryExposureKey.TemporaryExposureKeyBuilder {
|
|
||||||
var keyData = ByteArray(16)
|
var keyData = ByteArray(16)
|
||||||
SecureRandom().nextBytes(keyData)
|
SecureRandom().nextBytes(keyData)
|
||||||
setKeyData(keyData)
|
setKeyData(keyData)
|
||||||
setRollingPeriod(ROLLING_PERIOD)
|
setRollingStartIntervalNumber(intervalNumber)
|
||||||
return this
|
setRollingPeriod((ROLLING_PERIOD - getPeriodInDay(intervalNumber)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateCurrentTemporaryExposureKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder().generate().setCurrentRollingStartNumber().build()
|
fun generateCurrentDayTemporaryExposureKey(): TemporaryExposureKey = generateTemporaryExposureKey(currentDayRollingStartNumber).build()
|
||||||
|
fun generateIntraDayTemporaryExposureKey(intervalNumber: Int = currentIntervalNumber): TemporaryExposureKey = generateTemporaryExposureKey(intervalNumber).build()
|
||||||
|
|
||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
fun TemporaryExposureKey.generateRpiKey(): SecretKeySpec {
|
fun TemporaryExposureKey.generateRpiKey(): SecretKeySpec {
|
||||||
|
@ -15,14 +15,11 @@ import android.database.sqlite.SQLiteOpenHelper
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.android.gms.nearby.exposurenotification.CalibrationConfidence
|
|
||||||
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
|
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
|
||||||
import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
|
import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
|
||||||
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import okio.ByteString
|
import okio.ByteString
|
||||||
import org.json.JSONObject
|
|
||||||
import org.microg.gms.nearby.exposurenotification.Constants.TOKEN_A
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Runnable
|
import java.lang.Runnable
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@ -111,7 +108,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||||||
|
|
||||||
fun dailyCleanup(): Boolean = writableDatabase.run {
|
fun dailyCleanup(): Boolean = writableDatabase.run {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
val rollingStartTime = currentRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
|
val rollingStartTime = currentDayRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
|
||||||
val advertisements = delete(TABLE_ADVERTISEMENTS, "timestamp < ?", longArrayOf(rollingStartTime))
|
val advertisements = delete(TABLE_ADVERTISEMENTS, "timestamp < ?", longArrayOf(rollingStartTime))
|
||||||
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv")
|
Log.d(TAG, "Deleted on daily cleanup: $advertisements adv")
|
||||||
if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false
|
if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false
|
||||||
@ -533,8 +530,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findOwnKeyAt(rollingStartNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run {
|
private fun findOwnKeyAt(intervalNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run {
|
||||||
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber = ?", arrayOf(rollingStartNumber.toString()), null, null, null).use { cursor ->
|
val dayRollingStartNumber = getDayRollingStartNumber(intervalNumber)
|
||||||
|
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) < ?", arrayOf(dayRollingStartNumber.toString(), intervalNumber.toString()), null, null, "rollingStartNumber DESC").use { cursor ->
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
||||||
.setKeyData(cursor.getBlob(0))
|
.setKeyData(cursor.getBlob(0))
|
||||||
@ -602,18 +600,33 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val allKeys: List<TemporaryExposureKey> = readableDatabase.run {
|
fun exportKeys(database: SQLiteDatabase = writableDatabase): List<TemporaryExposureKey> = database.run {
|
||||||
val startRollingNumber = (currentRollingStartNumber - 14 * ROLLING_PERIOD)
|
database.beginTransactionNonExclusive()
|
||||||
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND rollingStartNumber < ?", arrayOf(startRollingNumber.toString(), currentIntervalNumber.toString()), null, null, null).use { cursor ->
|
try {
|
||||||
val list = arrayListOf<TemporaryExposureKey>()
|
val intervalNumber = currentIntervalNumber
|
||||||
while (cursor.moveToNext()) {
|
val key = findOwnKeyAt(intervalNumber, database)
|
||||||
list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
if (key != null && intervalNumber != key.rollingStartIntervalNumber) {
|
||||||
.setKeyData(cursor.getBlob(0))
|
// Rotate key
|
||||||
.setRollingStartIntervalNumber(cursor.getLong(1).toInt())
|
update(TABLE_TEK, ContentValues().apply {
|
||||||
.setRollingPeriod(cursor.getLong(2).toInt())
|
put("rollingPeriod", intervalNumber - key.rollingStartIntervalNumber)
|
||||||
.build())
|
}, "rollingStartNumber = ?", arrayOf(key.rollingStartIntervalNumber.toString()))
|
||||||
|
storeOwnKey(generateIntraDayTemporaryExposureKey(intervalNumber), database)
|
||||||
}
|
}
|
||||||
list
|
database.setTransactionSuccessful()
|
||||||
|
val startRollingNumber = (getDayRollingStartNumber(intervalNumber) - 14 * ROLLING_PERIOD)
|
||||||
|
query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) <= ?", arrayOf(startRollingNumber.toString(), intervalNumber.toString()), null, null, null).use { cursor ->
|
||||||
|
val list = arrayListOf<TemporaryExposureKey>()
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()
|
||||||
|
.setKeyData(cursor.getBlob(0))
|
||||||
|
.setRollingStartIntervalNumber(cursor.getLong(1).toInt())
|
||||||
|
.setRollingPeriod(cursor.getLong(2).toInt())
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
list
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
database.endTransaction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,9 +746,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||||||
private fun ensureTemporaryExposureKey(): TemporaryExposureKey = writableDatabase.let { database ->
|
private fun ensureTemporaryExposureKey(): TemporaryExposureKey = writableDatabase.let { database ->
|
||||||
database.beginTransactionNonExclusive()
|
database.beginTransactionNonExclusive()
|
||||||
try {
|
try {
|
||||||
var key = findOwnKeyAt(currentRollingStartNumber.toInt(), database)
|
var key = findOwnKeyAt(currentIntervalNumber.toInt(), database)
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
key = generateCurrentTemporaryExposureKey()
|
key = generateCurrentDayTemporaryExposureKey()
|
||||||
storeOwnKey(key, database)
|
storeOwnKey(key, database)
|
||||||
}
|
}
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
@ -747,7 +760,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
|
|||||||
|
|
||||||
val currentRpiId: UUID?
|
val currentRpiId: UUID?
|
||||||
get() {
|
get() {
|
||||||
val key = findOwnKeyAt(currentRollingStartNumber.toInt()) ?: return null
|
val key = findOwnKeyAt(currentIntervalNumber.toInt()) ?: return null
|
||||||
val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber.toInt()))
|
val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber.toInt()))
|
||||||
return UUID(buffer.long, buffer.long)
|
return UUID(buffer.long, buffer.long)
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val
|
|||||||
val status = confirmPermission(CONFIRM_ACTION_KEYS)
|
val status = confirmPermission(CONFIRM_ACTION_KEYS)
|
||||||
val response = when {
|
val response = when {
|
||||||
status.isSuccess -> ExposureDatabase.with(context) { database ->
|
status.isSuccess -> ExposureDatabase.with(context) { database ->
|
||||||
database.allKeys
|
database.exportKeys()
|
||||||
}
|
}
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user