Skip to content

Commit

Permalink
feat: Add resendLastTransfer() function in TransferSend manager (#278)
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarX authored Dec 20, 2024
2 parents f4c5bd3 + 1f6b74f commit 77dbccd
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import java.util.UUID
*
* There is 2 types of Request:
* - the standard request ([requestIntegrityVerdictToken]) that need a warm-up first ([warmUpTokenProvider])
* - the classic request ([requestClassicIntegrityVerdictToken]) that need additional Api checks
* - the classic request ([requestClassicIntegrityVerdictToken]) that need additional API checks
*/
class AppIntegrityManager(private val appContext: Context) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class AppIntegrityRepository {
"challenge_id" to challengeId,
)

// Add this line to test validation by api
// Add this line to test validation by API
// body["force_integrity_test"] = "true"

return post<ApiResponse<String>>(url = Url(AppIntegrityRoutes.requestApiIntegrityCheck), data = body)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class ImportFilesViewModel @Inject constructor(

fun sendTransfer() {
viewModelScope.launch(ioDispatcher) {
transferSendManager.sendTransfer(generateNewUploadSession())
transferSendManager.sendNewTransfer(generateNewUploadSession())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.A
import com.infomaniak.swisstransfer.ui.screen.newtransfer.ImportFilesViewModel.SendActionResult
import com.infomaniak.swisstransfer.workers.UploadWorker
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand All @@ -46,71 +45,65 @@ class TransferSendManager @Inject constructor(
private val uploadWorkerScheduler: UploadWorker.Scheduler,
) {

// TODO: Merge these two ui states in a single one for the whole flow of logic
// TODO: Merge these two UI states in a single one for the whole flow of logic
private val _sendActionResult = MutableStateFlow<SendActionResult?>(SendActionResult.NotStarted)
val sendActionResult = _sendActionResult.asStateFlow()

private val _integrityCheckResult = MutableStateFlow(AppIntegrityResult.Idle)
val integrityCheckResult = _integrityCheckResult.asStateFlow()

suspend fun sendTransfer(newUploadSession: NewUploadSession) {
suspend fun sendNewTransfer(newUploadSession: NewUploadSession) {
val uploadSession = uploadManager.createAndGetUpload(newUploadSession)
sendTransfer(uploadSession.uuid)
}

suspend fun resendLastTransfer() {
val uploadSessionUuid = uploadManager.getLastUpload()?.uuid ?: run {
SentryLog.e(TAG, "No last upload found")
return
}
sendTransfer(uploadSessionUuid)
}

private suspend fun sendTransfer(uploadSessionUuid: String) {
_integrityCheckResult.value = AppIntegrityResult.Ongoing

withIntegrityToken(
onSuccess = { attestationToken -> sendTransfer(newUploadSession, attestationToken) },
onRefused = { _integrityCheckResult.value = AppIntegrityResult.Fail },
onFailure = { exception ->
if (exception !is CancellationException) {
SentryLog.e(TAG, "Integrity token received an exception", exception)
} else {
SentryLog.i(TAG, "Integrity token received an exception", exception)
onSuccess = { attestationToken ->
runCatching {
_integrityCheckResult.value = AppIntegrityResult.Success
_sendActionResult.update { SendActionResult.Pending }

uploadManager.initUploadSession(
attestationHeaderName = AppIntegrityManager.ATTESTATION_TOKEN_HEADER,
attestationToken = attestationToken,
)!! // TODO: Handle ContainerErrorsException here
uploadWorkerScheduler.scheduleWork(uploadSessionUuid)
_sendActionResult.update {
val totalSize = importationFilesManager.importedFiles.value.sumOf { it.fileSize }
SendActionResult.Success(totalSize)
}
}.onFailure { exception ->
SentryLog.e(TAG, "Failed to start the upload", exception)
_sendActionResult.update { SendActionResult.Failure }
}
_sendActionResult.update { SendActionResult.Failure }
}
},
onRefused = { _integrityCheckResult.value = AppIntegrityResult.Fail },
)
}

private suspend fun sendTransfer(newUploadSession: NewUploadSession, attestationToken: String) {
_integrityCheckResult.value = AppIntegrityResult.Success
_sendActionResult.update { SendActionResult.Pending }

runCatching {
val uuid = uploadManager.createAndGetUpload(newUploadSession).uuid
uploadManager.initUploadSession(
attestationHeaderName = AppIntegrityManager.ATTESTATION_TOKEN_HEADER,
attestationToken = attestationToken,
)!! // TODO: Handle ContainerErrorsException here
uploadWorkerScheduler.scheduleWork(uuid)
_sendActionResult.update {
val totalSize = importationFilesManager.importedFiles.value.sumOf { it.fileSize }
SendActionResult.Success(totalSize)
}
}.onFailure { exception ->
SentryLog.e(TAG, "Failed to start the upload", exception)
_sendActionResult.update { SendActionResult.Failure }
}
}

//region App Integrity
private suspend inline fun withIntegrityToken(
onSuccess: (attestationToken: String) -> Unit,
onRefused: () -> Unit = {},
onFailure: (exception: Throwable) -> Unit = {},
) {
runCatching {
var attestationToken: String? = null

coroutineScope {
appIntegrityManager.getChallenge(
onSuccess = { launch { attestationToken = requestAppIntegrityToken(appIntegrityManager) } },
onFailure = {},
)
}

attestationToken?.let(onSuccess) ?: onRefused()
}.onFailure {
onFailure.invoke(it)
private suspend inline fun withIntegrityToken(onSuccess: (attestationToken: String) -> Unit, onRefused: () -> Unit = {}) {
var attestationToken: String? = null

coroutineScope {
appIntegrityManager.getChallenge(
onSuccess = { launch { attestationToken = requestAppIntegrityToken(appIntegrityManager) } },
onFailure = {},
)
}

attestationToken?.let(onSuccess) ?: onRefused()
}

private suspend fun requestAppIntegrityToken(appIntegrityManager: AppIntegrityManager): String? {
Expand All @@ -137,7 +130,7 @@ class TransferSendManager @Inject constructor(
packageName = BuildConfig.APPLICATION_ID,
targetUrl = sharedApiUrlCreator.createUploadContainerUrl,
onSuccess = { attestationToken ->
SentryLog.i(APP_INTEGRITY_MANAGER_TAG, "Api verdict check")
SentryLog.i(APP_INTEGRITY_MANAGER_TAG, "API verdict check")
Log.i(APP_INTEGRITY_MANAGER_TAG, "getApiIntegrityVerdict: $attestationToken")
token = attestationToken
},
Expand Down

0 comments on commit 77dbccd

Please sign in to comment.