mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Improve handling when own app lists at the server are defect
This commit is contained in:
parent
f3e83f9954
commit
56b7fe7e36
6 changed files with 260 additions and 188 deletions
|
@ -38,9 +38,6 @@ interface CryptContainerDao {
|
||||||
@Query("SELECT * FROM crypt_container_metadata WHERE category_id = :categoryId AND device_id IS NULL AND type = :type")
|
@Query("SELECT * FROM crypt_container_metadata WHERE category_id = :categoryId AND device_id IS NULL AND type = :type")
|
||||||
fun getCryptoMetadataSyncByCategoryId(categoryId: String, type: Int): CryptContainerMetadata?
|
fun getCryptoMetadataSyncByCategoryId(categoryId: String, type: Int): CryptContainerMetadata?
|
||||||
|
|
||||||
@Query("DELETE FROM crypt_container_metadata WHERE category_id IS NULL AND device_id = :deviceId AND type in (:types)")
|
|
||||||
fun removeDeviceCryptoMetadata(deviceId: String, types: List<Int>)
|
|
||||||
|
|
||||||
@Query("SELECT * FROM crypt_container_metadata WHERE status = :processingStatus")
|
@Query("SELECT * FROM crypt_container_metadata WHERE status = :processingStatus")
|
||||||
fun getMetadataByProcessingStatus(processingStatus: CryptContainerMetadata.ProcessingStatus): List<CryptContainerMetadata>
|
fun getMetadataByProcessingStatus(processingStatus: CryptContainerMetadata.ProcessingStatus): List<CryptContainerMetadata>
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,10 @@ data class CryptContainerMetadata (
|
||||||
nextCounter = 1,
|
nextCounter = 1,
|
||||||
currentGenerationFirstTimestamp = System.currentTimeMillis(),
|
currentGenerationFirstTimestamp = System.currentTimeMillis(),
|
||||||
currentGenerationKey = newKey
|
currentGenerationKey = newKey
|
||||||
)
|
),
|
||||||
|
type =
|
||||||
|
if (currentGenerationKey == null) PrepareEncryptionResult.Type.NewContainer
|
||||||
|
else PrepareEncryptionResult.Type.IncrementedGeneration
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
PrepareEncryptionResult(
|
PrepareEncryptionResult(
|
||||||
|
@ -128,15 +131,23 @@ data class CryptContainerMetadata (
|
||||||
),
|
),
|
||||||
newMetadata = copy(
|
newMetadata = copy(
|
||||||
nextCounter = nextCounter + 1
|
nextCounter = nextCounter + 1
|
||||||
)
|
),
|
||||||
|
type = PrepareEncryptionResult.Type.IncrementedCounter
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PrepareEncryptionResult (
|
data class PrepareEncryptionResult (
|
||||||
val params: CryptContainer.EncryptParameters,
|
val params: CryptContainer.EncryptParameters,
|
||||||
val newMetadata: CryptContainerMetadata
|
val newMetadata: CryptContainerMetadata,
|
||||||
)
|
val type: Type
|
||||||
|
) {
|
||||||
|
enum class Type {
|
||||||
|
NewContainer,
|
||||||
|
IncrementedGeneration,
|
||||||
|
IncrementedCounter
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CryptContainerMetadataProcessingStatusConverter {
|
class CryptContainerMetadataProcessingStatusConverter {
|
||||||
|
|
20
app/src/main/java/io/timelimit/android/extensions/Wire.kt
Normal file
20
app/src/main/java/io/timelimit/android/extensions/Wire.kt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.timelimit.android.extensions
|
||||||
|
|
||||||
|
import com.squareup.wire.Message
|
||||||
|
|
||||||
|
fun <M : Message<M, B>, B : Message.Builder<M, B>> Message<M, B>.encodedSize() = this.adapter.encodedSize(this as M)
|
|
@ -21,6 +21,7 @@ import io.timelimit.android.crypto.CryptContainer
|
||||||
import io.timelimit.android.data.Database
|
import io.timelimit.android.data.Database
|
||||||
import io.timelimit.android.data.model.CryptContainerData
|
import io.timelimit.android.data.model.CryptContainerData
|
||||||
import io.timelimit.android.data.model.CryptContainerMetadata
|
import io.timelimit.android.data.model.CryptContainerMetadata
|
||||||
|
import io.timelimit.android.extensions.encodedSize
|
||||||
import io.timelimit.android.logic.ServerApiLevelInfo
|
import io.timelimit.android.logic.ServerApiLevelInfo
|
||||||
import io.timelimit.android.proto.build
|
import io.timelimit.android.proto.build
|
||||||
import io.timelimit.android.proto.encodeDeflated
|
import io.timelimit.android.proto.encodeDeflated
|
||||||
|
@ -43,154 +44,165 @@ object CryptoAppListSync {
|
||||||
disableLegacySync: Boolean,
|
disableLegacySync: Boolean,
|
||||||
serverApiLevelInfo: ServerApiLevelInfo
|
serverApiLevelInfo: ServerApiLevelInfo
|
||||||
) {
|
) {
|
||||||
fun dispatch(action: AppLogicAction) {
|
val compressedDataSizeLimit =
|
||||||
|
if (serverApiLevelInfo.hasLevelOrIsOffline(5)) 1024 * 512
|
||||||
|
else 1024 * 256
|
||||||
|
|
||||||
|
fun dispatchSync(action: AppLogicAction) {
|
||||||
if (deviceState.isConnectedMode) {
|
if (deviceState.isConnectedMode) {
|
||||||
ApplyActionUtil.addAppLogicActionToDatabaseSync(action, database)
|
ApplyActionUtil.addAppLogicActionToDatabaseSync(action, database)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val compressedDataSizeLimit =
|
fun <T> prepareEncryption(encrypted: InstalledAppsUtil.Encrypted<T>?, type: Int, forceNewGeneration: Boolean = false) = if (encrypted == null) {
|
||||||
if (serverApiLevelInfo.hasLevelOrIsOffline(5)) 1024 * 512
|
val key = CryptContainer.EncryptParameters.generate()
|
||||||
else 1024 * 256
|
|
||||||
|
|
||||||
val savedCrypt = Threads.database.executeAndWait {
|
val metadata = CryptContainerMetadata.buildFor(
|
||||||
InstalledAppsUtil.getEncryptedInstalledAppsFromDatabaseSync(database, deviceState.id)
|
deviceId = deviceState.id,
|
||||||
|
categoryId = null,
|
||||||
|
type = type,
|
||||||
|
params = key
|
||||||
|
)
|
||||||
|
|
||||||
|
CryptContainerMetadata.PrepareEncryptionResult(key, metadata, CryptContainerMetadata.PrepareEncryptionResult.Type.NewContainer)
|
||||||
|
} else {
|
||||||
|
if (encrypted.meta.type != type) throw IllegalStateException()
|
||||||
|
|
||||||
|
encrypted.meta.copy(
|
||||||
|
status = CryptContainerMetadata.ProcessingStatus.Finished
|
||||||
|
).prepareEncryption(forceNewGeneration)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedCrypt == null) {
|
fun throwIfTooLarge(data: ByteArray) {
|
||||||
val baseKey = CryptContainer.EncryptParameters.generate()
|
data.size.let {
|
||||||
val diffKey = CryptContainer.EncryptParameters.generate()
|
if (it > compressedDataSizeLimit) throw TooLargeException(it)
|
||||||
|
|
||||||
val baseEncrypted = CryptContainer.encrypt(installed.encodeDeflated(), baseKey)
|
|
||||||
val diffEncrypted = CryptContainer.encrypt(SavedAppsDifferenceProto.build(baseEncrypted, InstalledAppsDifferenceProto()).encodeDeflated(), diffKey)
|
|
||||||
|
|
||||||
if (baseEncrypted.size > compressedDataSizeLimit) throw TooLargeException(baseEncrypted.size)
|
|
||||||
|
|
||||||
Threads.database.executeAndWait {
|
|
||||||
database.cryptContainer().removeDeviceCryptoMetadata(
|
|
||||||
deviceId = deviceState.id,
|
|
||||||
types = listOf(
|
|
||||||
CryptContainerMetadata.TYPE_APP_LIST_BASE,
|
|
||||||
CryptContainerMetadata.TYPE_APP_LIST_DIFF
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val baseId = database.cryptContainer().insertMetadata(
|
|
||||||
CryptContainerMetadata.buildFor(
|
|
||||||
deviceId = deviceState.id,
|
|
||||||
categoryId = null,
|
|
||||||
type = CryptContainerMetadata.TYPE_APP_LIST_BASE,
|
|
||||||
params = baseKey
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val diffId = database.cryptContainer().insertMetadata(
|
|
||||||
CryptContainerMetadata.buildFor(
|
|
||||||
deviceId = deviceState.id,
|
|
||||||
categoryId = null,
|
|
||||||
type = CryptContainerMetadata.TYPE_APP_LIST_DIFF,
|
|
||||||
params = diffKey
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
database.cryptContainer().insertData(
|
|
||||||
CryptContainerData(
|
|
||||||
cryptContainerId = baseId,
|
|
||||||
encryptedData = baseEncrypted
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
database.cryptContainer().insertData(
|
|
||||||
CryptContainerData(
|
|
||||||
cryptContainerId = diffId,
|
|
||||||
encryptedData = diffEncrypted
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
dispatch(UpdateInstalledAppsAction(
|
|
||||||
base = baseEncrypted,
|
|
||||||
diff = diffEncrypted,
|
|
||||||
wipe = disableLegacySync
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
syncUtil.requestImportantSync()
|
val savedCrypt = InstalledAppsUtil.getEncryptedInstalledAppsFromDatabase(database, deviceState.id)
|
||||||
} else {
|
|
||||||
val diffCrypto = AppsDifferenceUtil.calculateAppsDifference(savedCrypt.base, installed)
|
|
||||||
|
|
||||||
if (diffCrypto != savedCrypt.diff) {
|
val baseCryptConfig = prepareEncryption(
|
||||||
val baseSize = savedCrypt.base.adapter.encodedSize(savedCrypt.base)
|
encrypted = savedCrypt.base,
|
||||||
val diffSize = diffCrypto.adapter.encodedSize(diffCrypto)
|
type = CryptContainerMetadata.TYPE_APP_LIST_BASE
|
||||||
val needsNewBySize = diffSize >= baseSize / 10
|
)
|
||||||
val baseNeedsNewGeneration = savedCrypt.baseMeta.needsNewGeneration()
|
|
||||||
val diffNeedsNewGeneration = savedCrypt.diffMeta.needsNewGeneration() or baseNeedsNewGeneration
|
|
||||||
|
|
||||||
val diffCryptParams = savedCrypt.diffMeta.prepareEncryption(diffNeedsNewGeneration)
|
val diffCryptConfig = prepareEncryption(
|
||||||
|
encrypted = savedCrypt.diff,
|
||||||
|
type = CryptContainerMetadata.TYPE_APP_LIST_DIFF,
|
||||||
|
forceNewGeneration = baseCryptConfig.type != CryptContainerMetadata.PrepareEncryptionResult.Type.IncrementedCounter || savedCrypt.base?.decrypted == null
|
||||||
|
)
|
||||||
|
|
||||||
if (needsNewBySize or baseNeedsNewGeneration) {
|
val diffCrypto: InstalledAppsDifferenceProto? = if (savedCrypt.base?.decrypted == null) null
|
||||||
val baseCryptParams = savedCrypt.baseMeta.prepareEncryption(baseNeedsNewGeneration)
|
else AppsDifferenceUtil.calculateAppsDifference(savedCrypt.base.decrypted.data, installed)
|
||||||
|
|
||||||
val baseEncrypted = CryptContainer.encrypt(installed.encodeDeflated(), baseCryptParams.params)
|
if (
|
||||||
|
savedCrypt.base?.decrypted == null ||
|
||||||
|
savedCrypt.diff?.decrypted == null ||
|
||||||
|
diffCrypto != savedCrypt.diff.decrypted.data
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
savedCrypt.base?.decrypted == null ||
|
||||||
|
savedCrypt.diff?.decrypted == null ||
|
||||||
|
diffCrypto == null ||
|
||||||
|
baseCryptConfig.type != CryptContainerMetadata.PrepareEncryptionResult.Type.IncrementedCounter ||
|
||||||
|
diffCrypto.encodedSize() >= savedCrypt.base.decrypted.data.encodedSize() / 10
|
||||||
|
) {
|
||||||
|
val (baseEncrypted, diffEncrypted) = Threads.crypto.executeAndWait {
|
||||||
|
val baseEncrypted = CryptContainer.encrypt(
|
||||||
|
installed.encodeDeflated(),
|
||||||
|
baseCryptConfig.params
|
||||||
|
)
|
||||||
|
|
||||||
val diffEncrypted = CryptContainer.encrypt(
|
val diffEncrypted = CryptContainer.encrypt(
|
||||||
SavedAppsDifferenceProto.build(baseEncrypted, InstalledAppsDifferenceProto()).encodeDeflated(),
|
SavedAppsDifferenceProto.build(
|
||||||
diffCryptParams.params
|
baseEncrypted,
|
||||||
|
InstalledAppsDifferenceProto()
|
||||||
|
).encodeDeflated(),
|
||||||
|
diffCryptConfig.params
|
||||||
)
|
)
|
||||||
|
|
||||||
if (baseEncrypted.size > compressedDataSizeLimit) throw TooLargeException(baseEncrypted.size)
|
Pair(baseEncrypted, diffEncrypted)
|
||||||
|
}
|
||||||
|
|
||||||
Threads.database.executeAndWait {
|
throwIfTooLarge(baseEncrypted)
|
||||||
database.cryptContainer().updateMetadata(listOf(
|
throwIfTooLarge(diffEncrypted)
|
||||||
baseCryptParams.newMetadata,
|
|
||||||
diffCryptParams.newMetadata
|
|
||||||
))
|
|
||||||
|
|
||||||
database.cryptContainer().updateData(listOf(
|
Threads.database.executeAndWait {
|
||||||
|
if (savedCrypt.base == null) {
|
||||||
|
val baseId = database.cryptContainer().insertMetadata(baseCryptConfig.newMetadata)
|
||||||
|
|
||||||
|
database.cryptContainer().insertData(
|
||||||
CryptContainerData(
|
CryptContainerData(
|
||||||
cryptContainerId = savedCrypt.baseMeta.cryptContainerId,
|
cryptContainerId = baseId,
|
||||||
encryptedData = baseEncrypted
|
encryptedData = baseEncrypted
|
||||||
),
|
|
||||||
CryptContainerData(
|
|
||||||
cryptContainerId = savedCrypt.diffMeta.cryptContainerId,
|
|
||||||
encryptedData = diffEncrypted
|
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
} else {
|
||||||
|
database.cryptContainer().updateMetadata(baseCryptConfig.newMetadata)
|
||||||
|
|
||||||
dispatch(UpdateInstalledAppsAction(
|
database.cryptContainer().updateData(CryptContainerData(
|
||||||
base = baseEncrypted,
|
cryptContainerId = savedCrypt.base.meta.cryptContainerId,
|
||||||
diff = diffEncrypted,
|
encryptedData = baseEncrypted
|
||||||
wipe = disableLegacySync
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
syncUtil.requestImportantSync()
|
if (savedCrypt.diff == null) {
|
||||||
} else {
|
val diffId = database.cryptContainer().insertMetadata(diffCryptConfig.newMetadata)
|
||||||
val diffEncrypted = CryptContainer.encrypt(
|
|
||||||
SavedAppsDifferenceProto.build(savedCrypt.baseHeader, diffCrypto).encodeDeflated(),
|
|
||||||
diffCryptParams.params
|
|
||||||
)
|
|
||||||
|
|
||||||
if (diffEncrypted.size > compressedDataSizeLimit) throw TooLargeException(diffEncrypted.size)
|
database.cryptContainer().insertData(
|
||||||
|
|
||||||
Threads.database.executeAndWait {
|
|
||||||
database.cryptContainer().updateMetadata(diffCryptParams.newMetadata)
|
|
||||||
|
|
||||||
database.cryptContainer().updateData(
|
|
||||||
CryptContainerData(
|
CryptContainerData(
|
||||||
cryptContainerId = savedCrypt.diffMeta.cryptContainerId,
|
cryptContainerId = diffId,
|
||||||
encryptedData = diffEncrypted
|
encryptedData = diffEncrypted
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
database.cryptContainer().updateMetadata(diffCryptConfig.newMetadata)
|
||||||
|
|
||||||
dispatch(UpdateInstalledAppsAction(
|
database.cryptContainer().updateData(CryptContainerData(
|
||||||
base = null,
|
cryptContainerId = savedCrypt.diff.meta.cryptContainerId,
|
||||||
diff = diffEncrypted,
|
encryptedData = diffEncrypted
|
||||||
wipe = disableLegacySync
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
syncUtil.requestImportantSync()
|
dispatchSync(UpdateInstalledAppsAction(
|
||||||
|
base = baseEncrypted,
|
||||||
|
diff = diffEncrypted,
|
||||||
|
wipe = disableLegacySync
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncUtil.requestImportantSync()
|
||||||
|
} else {
|
||||||
|
val diffEncrypted = Threads.crypto.executeAndWait {
|
||||||
|
CryptContainer.encrypt(
|
||||||
|
SavedAppsDifferenceProto.build(
|
||||||
|
savedCrypt.base.decrypted.header,
|
||||||
|
diffCrypto
|
||||||
|
).encodeDeflated(),
|
||||||
|
diffCryptConfig.params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
throwIfTooLarge(diffEncrypted)
|
||||||
|
|
||||||
|
Threads.database.executeAndWait {
|
||||||
|
database.cryptContainer().updateMetadata(diffCryptConfig.newMetadata)
|
||||||
|
|
||||||
|
database.cryptContainer().updateData(
|
||||||
|
CryptContainerData(
|
||||||
|
cryptContainerId = savedCrypt.diff.meta.cryptContainerId,
|
||||||
|
encryptedData = diffEncrypted
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
dispatchSync(UpdateInstalledAppsAction(
|
||||||
|
base = null,
|
||||||
|
diff = diffEncrypted,
|
||||||
|
wipe = disableLegacySync
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
syncUtil.requestImportantSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,90 +45,114 @@ object InstalledAppsUtil {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEncryptedInstalledAppsFromDatabaseSync(database: Database, deviceId: String): DecryptedInstalledApps? {
|
suspend fun getEncryptedInstalledAppsFromDatabase(database: Database, deviceId: String): EncryptedInstalledApps {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Log.d(LOG_TAG, "getEncryptedInstalledAppsFromDatabaseSync()")
|
Log.d(LOG_TAG, "getEncryptedInstalledAppsFromDatabase()")
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseValue = database.cryptContainer().getCryptoFullDataSyncByDeviceId(
|
val (baseValue, diffValue) = Threads.database.executeAndWait {
|
||||||
deviceId = deviceId,
|
database.runInTransaction {
|
||||||
type = CryptContainerMetadata.TYPE_APP_LIST_BASE
|
val baseValue = database.cryptContainer().getCryptoFullDataSyncByDeviceId(
|
||||||
)
|
deviceId = deviceId,
|
||||||
|
type = CryptContainerMetadata.TYPE_APP_LIST_BASE
|
||||||
|
)
|
||||||
|
|
||||||
val diffValue = database.cryptContainer().getCryptoFullDataSyncByDeviceId(
|
val diffValue = database.cryptContainer().getCryptoFullDataSyncByDeviceId(
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
type = CryptContainerMetadata.TYPE_APP_LIST_DIFF
|
type = CryptContainerMetadata.TYPE_APP_LIST_DIFF
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
Pair(baseValue, diffValue)
|
||||||
baseValue == null ||
|
}
|
||||||
baseValue.metadata.currentGenerationKey == null ||
|
}
|
||||||
baseValue.metadata.status != CryptContainerMetadata.ProcessingStatus.Finished ||
|
|
||||||
diffValue == null ||
|
return Threads.crypto.executeAndWait {
|
||||||
diffValue.metadata.currentGenerationKey == null ||
|
val baseDecrypted = try {
|
||||||
diffValue.metadata.status != CryptContainerMetadata.ProcessingStatus.Finished
|
if (
|
||||||
) {
|
baseValue != null &&
|
||||||
if (BuildConfig.DEBUG) {
|
baseValue.metadata.currentGenerationKey != null &&
|
||||||
Log.d(LOG_TAG, "incomplete data")
|
baseValue.metadata.status == CryptContainerMetadata.ProcessingStatus.Finished
|
||||||
|
) {
|
||||||
|
val baseHeader = CryptContainer.Header.read(baseValue.encryptedData)
|
||||||
|
|
||||||
|
val baseDecrypted = CryptContainer.decrypt(
|
||||||
|
baseValue.metadata.currentGenerationKey,
|
||||||
|
baseValue.encryptedData
|
||||||
|
)
|
||||||
|
|
||||||
|
val baseData = InstalledAppsProto.ADAPTER.decodeInflated(baseDecrypted)
|
||||||
|
|
||||||
|
Decrypted(
|
||||||
|
data = baseData,
|
||||||
|
header = baseHeader
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
} catch (ex: CryptException) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "could not decrypt previous base data", ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
null
|
||||||
|
} catch (ex: IOException) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "could not decode previous base data", ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
val diffDecrypted = try {
|
||||||
}
|
if (
|
||||||
|
diffValue != null &&
|
||||||
|
diffValue.metadata.currentGenerationKey != null &&
|
||||||
|
diffValue.metadata.status == CryptContainerMetadata.ProcessingStatus.Finished
|
||||||
|
) {
|
||||||
|
val diffHeader = CryptContainer.Header.read(diffValue.encryptedData)
|
||||||
|
|
||||||
val (baseHeader, baseDecrypted, diffDecrypted) = try {
|
val diffDecrypted = CryptContainer.decrypt(
|
||||||
val baseHeader = CryptContainer.Header.read(baseValue.encryptedData)
|
diffValue.metadata.currentGenerationKey,
|
||||||
|
diffValue.encryptedData
|
||||||
|
)
|
||||||
|
|
||||||
val baseDecrypted = CryptContainer.decrypt(
|
val diffData =
|
||||||
baseValue.metadata.currentGenerationKey,
|
SavedAppsDifferenceProto.ADAPTER.decodeInflated(diffDecrypted).apps
|
||||||
baseValue.encryptedData
|
?: InstalledAppsDifferenceProto()
|
||||||
|
|
||||||
|
Decrypted(
|
||||||
|
data = diffData,
|
||||||
|
header = diffHeader
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
} catch (ex: CryptException) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "could not decrypt previous diff data", ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
null
|
||||||
|
} catch (ex: IOException) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "could not decode previous diff data", ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptedInstalledApps(
|
||||||
|
base = baseValue?.let { Encrypted(it.metadata, baseDecrypted) },
|
||||||
|
diff = diffValue?.let { Encrypted(it.metadata, diffDecrypted) }
|
||||||
)
|
)
|
||||||
|
|
||||||
val diffDecrypted = CryptContainer.decrypt(
|
|
||||||
diffValue.metadata.currentGenerationKey,
|
|
||||||
diffValue.encryptedData
|
|
||||||
)
|
|
||||||
|
|
||||||
Triple(baseHeader, baseDecrypted, diffDecrypted)
|
|
||||||
} catch (ex: CryptException) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Log.d(LOG_TAG, "could not decrypt previous data", ex)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val (base, diff) = try {
|
|
||||||
val base = InstalledAppsProto.ADAPTER.decodeInflated(baseDecrypted)
|
|
||||||
|
|
||||||
val diff = SavedAppsDifferenceProto.ADAPTER.decodeInflated(diffDecrypted).apps
|
|
||||||
?: InstalledAppsDifferenceProto()
|
|
||||||
|
|
||||||
Pair(base, diff)
|
|
||||||
} catch (ex: IOException) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Log.d(LOG_TAG, "could not decode data", ex)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return DecryptedInstalledApps(
|
|
||||||
base = base,
|
|
||||||
baseMeta = baseValue.metadata,
|
|
||||||
baseHeader = baseHeader,
|
|
||||||
diff = diff,
|
|
||||||
diffMeta = diffValue.metadata
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DecryptedInstalledApps(
|
data class EncryptedInstalledApps(
|
||||||
val base: InstalledAppsProto,
|
val base: Encrypted<InstalledAppsProto>?,
|
||||||
val baseHeader: CryptContainer.Header,
|
val diff: Encrypted<InstalledAppsDifferenceProto>?
|
||||||
val baseMeta: CryptContainerMetadata,
|
|
||||||
val diff: InstalledAppsDifferenceProto,
|
|
||||||
val diffMeta: CryptContainerMetadata
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class Encrypted<T>(val meta: CryptContainerMetadata, val decrypted: Decrypted<T>?)
|
||||||
|
|
||||||
|
data class Decrypted<T>(val data: T, val header: CryptContainer.Header)
|
||||||
|
|
||||||
suspend fun getInstalledAppsFromOs(appLogic: AppLogic, deviceState: DeviceState): InstalledAppsProto {
|
suspend fun getInstalledAppsFromOs(appLogic: AppLogic, deviceState: DeviceState): InstalledAppsProto {
|
||||||
val apps = kotlin.run {
|
val apps = kotlin.run {
|
||||||
val currentlyInstalled = Threads.backgroundOSInteraction.executeAndWait {
|
val currentlyInstalled = Threads.backgroundOSInteraction.executeAndWait {
|
||||||
|
|
|
@ -59,7 +59,15 @@ object CryptDataHandler {
|
||||||
} else oldItem.copy(serverVersion = data.version)
|
} else oldItem.copy(serverVersion = data.version)
|
||||||
|
|
||||||
if (deviceId == database.config().getOwnDeviceIdSync()) {
|
if (deviceId == database.config().getOwnDeviceIdSync()) {
|
||||||
database.cryptContainer().updateMetadata(currentItem)
|
val updatedItem = if (isUnmodified)
|
||||||
|
currentItem
|
||||||
|
else
|
||||||
|
// this tells the sync logic to not use the existing encrypted data and start a new generation
|
||||||
|
// there is no need to actually save the data from the server because it is not used at all
|
||||||
|
// the DecryptProcessor ignores data for the device itself
|
||||||
|
currentItem.copy(status = CryptContainerMetadata.ProcessingStatus.Unprocessed)
|
||||||
|
|
||||||
|
database.cryptContainer().updateMetadata(updatedItem)
|
||||||
|
|
||||||
return Result(didCreateKeyRequests = false)
|
return Result(didCreateKeyRequests = false)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue