Loading app/src/main/java/foundation/e/apps/api/DownloadManager.kt +22 −1 Original line number Diff line number Diff line Loading @@ -127,11 +127,32 @@ class DownloadManager @Inject constructor( } } private fun tickerFlow(downloadId: Long, period: Duration, initialDelay: Duration = Duration.ZERO) = flow { private fun tickerFlow( downloadId: Long, period: Duration, initialDelay: Duration = Duration.ZERO ) = flow { delay(initialDelay) while (downloadsMaps[downloadId]!!) { emit(Unit) delay(period) } } fun getDownloadStatus(downloadId: Long): Int { try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) Timber.d("Download Failed: downloadId: $downloadId $status") return status } } } catch (e: Exception) { e.printStackTrace() } return DownloadManager.STATUS_FAILED } } app/src/main/java/foundation/e/apps/api/cleanapk/ApkSignatureManager.kt +10 −5 Original line number Diff line number Diff line Loading @@ -35,11 +35,16 @@ import java.security.Security object ApkSignatureManager { fun verifyFdroidSignature(context: Context, apkFilePath: String, signature: String): Boolean { Security.addProvider(BouncyCastleProvider()) try { return verifyAPKSignature( BufferedInputStream(FileInputStream(apkFilePath)), signature.byteInputStream(Charsets.UTF_8), context.assets.open("f-droid.org-signing-key.gpg") ) } catch (e: Exception) { e.printStackTrace() } return false } private fun verifyAPKSignature( Loading app/src/main/java/foundation/e/apps/manager/download/DownloadManagerUtils.kt +27 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.manager.download import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.api.DownloadManager import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.fused.FusedManagerRepository import foundation.e.apps.utils.enums.Origin Loading @@ -33,11 +34,13 @@ import kotlinx.coroutines.sync.withLock import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton import android.app.DownloadManager as androidDownloadManager @Singleton class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, private val fusedManagerRepository: FusedManagerRepository, @ApplicationContext private val context: Context private val downloadManager: DownloadManager ) { private val TAG = DownloadManagerUtils::class.java.simpleName private val mutex = Mutex() Loading @@ -57,11 +60,12 @@ class DownloadManagerUtils @Inject constructor( delay(1500) // Waiting for downloadmanager to publish the progress of last bytes val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId) if (fusedDownload.id.isNotEmpty()) { fusedDownload.downloadIdMap[downloadId] = true fusedManagerRepository.updateFusedDownload(fusedDownload) val downloaded = fusedDownload.downloadIdMap.values.filter { it }.size Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $downloaded/${fusedDownload.downloadIdMap.size}") if (downloaded == fusedDownload.downloadIdMap.size && checkCleanApkSignatureOK(fusedDownload)) { updateDownloadIdMap(fusedDownload, downloadId) val numberOfDownloadedItems = fusedDownload.downloadIdMap.values.filter { it }.size Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") if (validateDownload(numberOfDownloadedItems, fusedDownload, downloadId)) { Timber.d("===> Download is completed for: ${fusedDownload.name}") fusedManagerRepository.moveOBBFileToOBBDirectory(fusedDownload) fusedDownload.status = Status.DOWNLOADED fusedManagerRepository.updateFusedDownload(fusedDownload) Loading @@ -71,6 +75,23 @@ class DownloadManagerUtils @Inject constructor( } } private suspend fun validateDownload( numberOfDownloadedItems: Int, fusedDownload: FusedDownload, downloadId: Long ) = downloadManager.getDownloadStatus(downloadId) == androidDownloadManager.STATUS_SUCCESSFUL && numberOfDownloadedItems == fusedDownload.downloadIdMap.size && checkCleanApkSignatureOK( fusedDownload ) private suspend fun updateDownloadIdMap( fusedDownload: FusedDownload, downloadId: Long ) { fusedDownload.downloadIdMap[downloadId] = true fusedManagerRepository.updateFusedDownload(fusedDownload) } private suspend fun checkCleanApkSignatureOK(fusedDownload: FusedDownload): Boolean { if (fusedDownload.origin != Origin.CLEANAPK || fusedManagerRepository.isFdroidApplicationSigned( context, Loading app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ class UpdatesWorker @AssistedInject constructor( val isConnectedToUnmeteredNetwork = isConnectedToUnmeteredNetwork(applicationContext) val authData = getAuthData() val appsNeededToUpdate = updatesManagerRepository.getUpdates(authData).first if (shouldShowNotification) { if (isAutoUpdate && shouldShowNotification) { handleNotification(appsNeededToUpdate.size, isConnectedToUnmeteredNetwork) } Loading Loading
app/src/main/java/foundation/e/apps/api/DownloadManager.kt +22 −1 Original line number Diff line number Diff line Loading @@ -127,11 +127,32 @@ class DownloadManager @Inject constructor( } } private fun tickerFlow(downloadId: Long, period: Duration, initialDelay: Duration = Duration.ZERO) = flow { private fun tickerFlow( downloadId: Long, period: Duration, initialDelay: Duration = Duration.ZERO ) = flow { delay(initialDelay) while (downloadsMaps[downloadId]!!) { emit(Unit) delay(period) } } fun getDownloadStatus(downloadId: Long): Int { try { downloadManager.query(downloadManagerQuery.setFilterById(downloadId)) .use { cursor -> if (cursor.moveToFirst()) { val status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) Timber.d("Download Failed: downloadId: $downloadId $status") return status } } } catch (e: Exception) { e.printStackTrace() } return DownloadManager.STATUS_FAILED } }
app/src/main/java/foundation/e/apps/api/cleanapk/ApkSignatureManager.kt +10 −5 Original line number Diff line number Diff line Loading @@ -35,11 +35,16 @@ import java.security.Security object ApkSignatureManager { fun verifyFdroidSignature(context: Context, apkFilePath: String, signature: String): Boolean { Security.addProvider(BouncyCastleProvider()) try { return verifyAPKSignature( BufferedInputStream(FileInputStream(apkFilePath)), signature.byteInputStream(Charsets.UTF_8), context.assets.open("f-droid.org-signing-key.gpg") ) } catch (e: Exception) { e.printStackTrace() } return false } private fun verifyAPKSignature( Loading
app/src/main/java/foundation/e/apps/manager/download/DownloadManagerUtils.kt +27 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.manager.download import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.api.DownloadManager import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.fused.FusedManagerRepository import foundation.e.apps.utils.enums.Origin Loading @@ -33,11 +34,13 @@ import kotlinx.coroutines.sync.withLock import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton import android.app.DownloadManager as androidDownloadManager @Singleton class DownloadManagerUtils @Inject constructor( @ApplicationContext private val context: Context, private val fusedManagerRepository: FusedManagerRepository, @ApplicationContext private val context: Context private val downloadManager: DownloadManager ) { private val TAG = DownloadManagerUtils::class.java.simpleName private val mutex = Mutex() Loading @@ -57,11 +60,12 @@ class DownloadManagerUtils @Inject constructor( delay(1500) // Waiting for downloadmanager to publish the progress of last bytes val fusedDownload = fusedManagerRepository.getFusedDownload(downloadId) if (fusedDownload.id.isNotEmpty()) { fusedDownload.downloadIdMap[downloadId] = true fusedManagerRepository.updateFusedDownload(fusedDownload) val downloaded = fusedDownload.downloadIdMap.values.filter { it }.size Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $downloaded/${fusedDownload.downloadIdMap.size}") if (downloaded == fusedDownload.downloadIdMap.size && checkCleanApkSignatureOK(fusedDownload)) { updateDownloadIdMap(fusedDownload, downloadId) val numberOfDownloadedItems = fusedDownload.downloadIdMap.values.filter { it }.size Timber.d("===> updateDownloadStatus: ${fusedDownload.name}: $downloadId: $numberOfDownloadedItems/${fusedDownload.downloadIdMap.size}") if (validateDownload(numberOfDownloadedItems, fusedDownload, downloadId)) { Timber.d("===> Download is completed for: ${fusedDownload.name}") fusedManagerRepository.moveOBBFileToOBBDirectory(fusedDownload) fusedDownload.status = Status.DOWNLOADED fusedManagerRepository.updateFusedDownload(fusedDownload) Loading @@ -71,6 +75,23 @@ class DownloadManagerUtils @Inject constructor( } } private suspend fun validateDownload( numberOfDownloadedItems: Int, fusedDownload: FusedDownload, downloadId: Long ) = downloadManager.getDownloadStatus(downloadId) == androidDownloadManager.STATUS_SUCCESSFUL && numberOfDownloadedItems == fusedDownload.downloadIdMap.size && checkCleanApkSignatureOK( fusedDownload ) private suspend fun updateDownloadIdMap( fusedDownload: FusedDownload, downloadId: Long ) { fusedDownload.downloadIdMap[downloadId] = true fusedManagerRepository.updateFusedDownload(fusedDownload) } private suspend fun checkCleanApkSignatureOK(fusedDownload: FusedDownload): Boolean { if (fusedDownload.origin != Origin.CLEANAPK || fusedManagerRepository.isFdroidApplicationSigned( context, Loading
app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ class UpdatesWorker @AssistedInject constructor( val isConnectedToUnmeteredNetwork = isConnectedToUnmeteredNetwork(applicationContext) val authData = getAuthData() val appsNeededToUpdate = updatesManagerRepository.getUpdates(authData).first if (shouldShowNotification) { if (isAutoUpdate && shouldShowNotification) { handleNotification(appsNeededToUpdate.size, isConnectedToUnmeteredNetwork) } Loading