diff --git a/build.gradle b/build.gradle index cdb486f93..55e719ae6 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.5.16' + androidVersionName = '1.5.17' } repositories { mavenCentral() diff --git a/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java index 277858d24..f2bb16fa7 100644 --- a/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java +++ b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java @@ -4,6 +4,7 @@ import org.cryptomator.data.cloud.dropbox.DropboxCloudContentRepositoryFactory; import org.cryptomator.data.cloud.local.LocalStorageContentRepositoryFactory; import org.cryptomator.data.cloud.onedrive.OnedriveCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.pcloud.PCloudContentRepositoryFactory; import org.cryptomator.data.cloud.webdav.WebDavCloudContentRepositoryFactory; import org.cryptomator.data.repository.CloudContentRepositoryFactory; import org.jetbrains.annotations.NotNull; @@ -23,12 +24,14 @@ public class CloudContentRepositoryFactories implements Iterable -
  • Fixed creating new vaults in pCloud
  • -
  • Fixed license screen in settings
  • +
  • Fixed pCloud login using F-Droid
  • \ No newline at end of file diff --git a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index 5bdc211c7..61a059953 100644 --- a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -2,17 +2,34 @@ package org.cryptomator.presentation.presenter import android.Manifest import android.accounts.AccountManager +import android.content.Intent +import android.widget.Toast import com.dropbox.core.android.Auth +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 import org.cryptomator.data.util.X509CertificateHelper -import org.cryptomator.domain.* +import org.cryptomator.domain.Cloud +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 import org.cryptomator.domain.exception.NetworkConnectionException -import org.cryptomator.domain.exception.authentication.* +import org.cryptomator.domain.exception.authentication.AuthenticationException +import org.cryptomator.domain.exception.authentication.WebDavCertificateUntrustedAuthenticationException +import org.cryptomator.domain.exception.authentication.WebDavNotSupportedException +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 @@ -20,23 +37,32 @@ import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.exception.PermissionNotGrantedException import org.cryptomator.presentation.intent.AuthenticateCloudIntent -import org.cryptomator.presentation.model.* +import org.cryptomator.presentation.model.CloudModel +import org.cryptomator.presentation.model.CloudTypeModel +import org.cryptomator.presentation.model.ProgressModel +import org.cryptomator.presentation.model.ProgressStateModel +import org.cryptomator.presentation.model.WebDavCloudModel import org.cryptomator.presentation.model.mappers.CloudModelMapper import org.cryptomator.presentation.ui.activity.view.AuthenticateCloudView -import org.cryptomator.presentation.workflow.* +import org.cryptomator.presentation.workflow.ActivityResult +import org.cryptomator.presentation.workflow.AddExistingVaultWorkflow +import org.cryptomator.presentation.workflow.CreateNewVaultWorkflow +import org.cryptomator.presentation.workflow.PermissionsResult +import org.cryptomator.presentation.workflow.Workflow import org.cryptomator.util.ExceptionUtil import org.cryptomator.util.crypto.CredentialCryptor -import timber.log.Timber import java.security.cert.CertificateEncodingException import java.security.cert.CertificateException import java.security.cert.X509Certificate import javax.inject.Inject +import timber.log.Timber @PerView 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) { @@ -44,6 +70,7 @@ class AuthenticateCloudPresenter @Inject constructor( // private val strategies = arrayOf( // DropboxAuthStrategy(), // OnedriveAuthStrategy(), // + PCloudAuthStrategy(), // WebDAVAuthStrategy(), // LocalStorageAuthStrategy() // ) @@ -221,6 +248,102 @@ 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) { + when { + 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 { override fun supports(cloud: CloudModel): Boolean { @@ -342,6 +465,6 @@ class AuthenticateCloudPresenter @Inject constructor( // } init { - unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getUsernameUseCase) + unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getCloudsUseCase, getUsernameUseCase) } }