diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 67ef7c01..6ef89ee7 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ An error occurred Authentication failed + Authentication failed, please login using %1$s No network connection Wrong password A file or folder already exists. diff --git a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index a1045799..8b228d10 100644 --- a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -3,9 +3,15 @@ package org.cryptomator.presentation.presenter import android.Manifest import android.accounts.AccountManager import android.content.ActivityNotFoundException +import android.content.Intent +import android.widget.Toast import com.dropbox.core.android.Auth import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential import com.google.api.services.drive.DriveScopes +import com.pcloud.sdk.AuthorizationActivity +import com.pcloud.sdk.AuthorizationData +import com.pcloud.sdk.AuthorizationRequest +import com.pcloud.sdk.AuthorizationResult import org.cryptomator.data.cloud.onedrive.OnedriveClientFactory import org.cryptomator.data.cloud.onedrive.graph.ClientException import org.cryptomator.data.cloud.onedrive.graph.ICallback @@ -15,6 +21,7 @@ import org.cryptomator.domain.CloudType import org.cryptomator.domain.DropboxCloud import org.cryptomator.domain.GoogleDriveCloud import org.cryptomator.domain.OnedriveCloud +import org.cryptomator.domain.PCloud import org.cryptomator.domain.WebDavCloud import org.cryptomator.domain.di.PerView import org.cryptomator.domain.exception.FatalBackendException @@ -25,6 +32,7 @@ import org.cryptomator.domain.exception.authentication.WebDavNotSupportedExcepti import org.cryptomator.domain.exception.authentication.WebDavServerNotFoundException import org.cryptomator.domain.exception.authentication.WrongCredentialsException import org.cryptomator.domain.usecases.cloud.AddOrChangeCloudConnectionUseCase +import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase import org.cryptomator.domain.usecases.cloud.GetUsernameUseCase import org.cryptomator.generator.Callback import org.cryptomator.presentation.BuildConfig @@ -34,7 +42,6 @@ import org.cryptomator.presentation.exception.PermissionNotGrantedException import org.cryptomator.presentation.intent.AuthenticateCloudIntent import org.cryptomator.presentation.model.CloudModel import org.cryptomator.presentation.model.CloudTypeModel -import org.cryptomator.presentation.model.PCloudModel import org.cryptomator.presentation.model.ProgressModel import org.cryptomator.presentation.model.ProgressStateModel import org.cryptomator.presentation.model.WebDavCloudModel @@ -58,6 +65,7 @@ class AuthenticateCloudPresenter @Inject constructor( // exceptionHandlers: ExceptionHandlers, // private val cloudModelMapper: CloudModelMapper, // private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, // + private val getCloudsUseCase: GetCloudsUseCase, // private val getUsernameUseCase: GetUsernameUseCase, // private val addExistingVaultWorkflow: AddExistingVaultWorkflow, // private val createNewVaultWorkflow: CreateNewVaultWorkflow) : Presenter(exceptionHandlers) { @@ -286,22 +294,98 @@ class AuthenticateCloudPresenter @Inject constructor( // private inner class PCloudAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { return cloud.cloudType() == CloudTypeModel.PCLOUD } override fun resumed(intent: AuthenticateCloudIntent) { - handlePCloudAuthenticationExceptionIfRequired(intent.cloud() as PCloudModel, intent.error()) - } - - private fun handlePCloudAuthenticationExceptionIfRequired(cloud: PCloudModel, e: AuthenticationException) { - Timber.tag("AuthicateCloudPrester").e(e) when { - ExceptionUtil.contains(e, WrongCredentialsException::class.java) -> { - failAuthentication(cloud.name()) + ExceptionUtil.contains(intent.error(), WrongCredentialsException::class.java) -> { + if (!authenticationStarted) { + startAuthentication() + Toast.makeText( + context(), + String.format(getString(R.string.error_authentication_failed_re_authenticate), intent.cloud().username()), + Toast.LENGTH_LONG).show() + } + } + else -> { + Timber.tag("AuthicateCloudPrester").e(intent.error()) + failAuthentication(intent.cloud().name()) } } } + + private fun startAuthentication() { + authenticationStarted = true + val authIntent: Intent = AuthorizationActivity.createIntent( + context(), + AuthorizationRequest.create() + .setType(AuthorizationRequest.Type.TOKEN) + .setClientId(BuildConfig.PCLOUD_CLIENT_ID) + .setForceAccessApproval(true) + .addPermission("manageshares") + .build()) + requestActivityResult(ActivityResultCallbacks.pCloudReAuthenticationFinished(), // + authIntent) + } + } + + @Callback + fun pCloudReAuthenticationFinished(activityResult: ActivityResult) { + val authData: AuthorizationData = AuthorizationActivity.getResult(activityResult.intent()) + val result: AuthorizationResult = authData.result + + when (result) { + AuthorizationResult.ACCESS_GRANTED -> { + val accessToken: String = CredentialCryptor // + .getInstance(context()) // + .encrypt(authData.token) + val pCloudSkeleton: PCloud = PCloud.aPCloud() // + .withAccessToken(accessToken) + .withUrl(authData.apiHost) + .build(); + getUsernameUseCase // + .withCloud(pCloudSkeleton) // + .run(object : DefaultResultHandler() { + override fun onSuccess(username: String?) { + prepareForSavingPCloud(PCloud.aCopyOf(pCloudSkeleton).withUsername(username).build()) + } + }) + } + AuthorizationResult.ACCESS_DENIED -> { + Timber.tag("CloudConnListPresenter").e("Account access denied") + view?.showMessage(String.format(getString(R.string.screen_authenticate_auth_authentication_failed), getString(R.string.cloud_names_pcloud))) + } + AuthorizationResult.AUTH_ERROR -> { + Timber.tag("CloudConnListPresenter").e("""Account access grant error: ${authData.errorMessage}""".trimIndent()) + view?.showMessage(String.format(getString(R.string.screen_authenticate_auth_authentication_failed), getString(R.string.cloud_names_pcloud))) + } + AuthorizationResult.CANCELLED -> { + Timber.tag("CloudConnListPresenter").i("Account access grant cancelled") + view?.showMessage(String.format(getString(R.string.screen_authenticate_auth_authentication_failed), getString(R.string.cloud_names_pcloud))) + } + } + } + + fun prepareForSavingPCloud(cloud: PCloud) { + getCloudsUseCase // + .withCloudType(cloud.type()) // + .run(object : DefaultResultHandler>() { + override fun onSuccess(clouds: List) { + clouds.firstOrNull { + (it as PCloud).username() == cloud.username() + }?.let { + it as PCloud + succeedAuthenticationWith(PCloud.aCopyOf(it) // + .withUrl(cloud.url()) + .withAccessToken(cloud.accessToken()) + .build()) + } ?: succeedAuthenticationWith(cloud) + } + }) } private inner class WebDAVAuthStrategy : AuthStrategy { @@ -425,6 +509,6 @@ class AuthenticateCloudPresenter @Inject constructor( // } init { - unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getUsernameUseCase) + unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getCloudsUseCase, getUsernameUseCase) } }