feat: add authentication for pCloud (including UI)
This commit is contained in:
parent
6a249056b0
commit
550415627e
@ -0,0 +1,23 @@
|
||||
package org.cryptomator.domain.usecases.cloud;
|
||||
|
||||
import org.cryptomator.domain.PCloudCloud;
|
||||
import org.cryptomator.domain.exception.BackendException;
|
||||
import org.cryptomator.domain.repository.CloudContentRepository;
|
||||
import org.cryptomator.generator.Parameter;
|
||||
import org.cryptomator.generator.UseCase;
|
||||
|
||||
@UseCase
|
||||
class ConnectToPCloud {
|
||||
|
||||
private final CloudContentRepository cloudContentRepository;
|
||||
private final PCloudCloud cloud;
|
||||
|
||||
public ConnectToPCloud(CloudContentRepository cloudContentRepository, @Parameter PCloudCloud cloud) {
|
||||
this.cloudContentRepository = cloudContentRepository;
|
||||
this.cloud = cloud;
|
||||
}
|
||||
|
||||
public void execute() throws BackendException {
|
||||
cloudContentRepository.checkAuthenticationAndRetrieveCurrentAccount(cloud);
|
||||
}
|
||||
}
|
@ -50,7 +50,11 @@ android {
|
||||
useProguard false
|
||||
|
||||
buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\""
|
||||
manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY')]
|
||||
buildConfigField "String", "PCLOUD_CLIENT_ID", "\"" + getApiKey('PCLOUD_CLIENT_ID') + "\""
|
||||
manifestPlaceholders = [
|
||||
DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY'),
|
||||
PCLOUD_CLIENT_ID: getApiKey('PCLOUD_CLIENT_ID')
|
||||
]
|
||||
|
||||
resValue "string", "app_id", androidApplicationId
|
||||
}
|
||||
@ -64,7 +68,11 @@ android {
|
||||
testCoverageEnabled false
|
||||
|
||||
buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY_DEBUG') + "\""
|
||||
manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY_DEBUG')]
|
||||
buildConfigField "String", "PCLOUD_CLIENT_ID", "\"" + getApiKey('PCLOUD_CLIENT_ID_DEBUG') + "\""
|
||||
manifestPlaceholders = [
|
||||
DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY_DEBUG'),
|
||||
PCLOUD_CLIENT_ID: getApiKey('PCLOUD_CLIENT_ID_DEBUG')
|
||||
]
|
||||
|
||||
applicationIdSuffix ".debug"
|
||||
versionNameSuffix '-DEBUG'
|
||||
|
@ -4,14 +4,21 @@ import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.pcloud.sdk.AuthorizationActivity
|
||||
import com.pcloud.sdk.AuthorizationData
|
||||
import com.pcloud.sdk.AuthorizationRequest
|
||||
import com.pcloud.sdk.AuthorizationResult
|
||||
import org.cryptomator.domain.Cloud
|
||||
import org.cryptomator.domain.LocalStorageCloud
|
||||
import org.cryptomator.domain.PCloudCloud
|
||||
import org.cryptomator.domain.Vault
|
||||
import org.cryptomator.domain.di.PerView
|
||||
import org.cryptomator.domain.usecases.cloud.AddOrChangeCloudConnectionUseCase
|
||||
import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase
|
||||
import org.cryptomator.domain.usecases.cloud.GetUsernameUseCase
|
||||
import org.cryptomator.domain.usecases.cloud.RemoveCloudUseCase
|
||||
import org.cryptomator.domain.usecases.vault.DeleteVaultUseCase
|
||||
import org.cryptomator.domain.usecases.vault.GetVaultListUseCase
|
||||
@ -26,6 +33,7 @@ import org.cryptomator.presentation.model.WebDavCloudModel
|
||||
import org.cryptomator.presentation.model.mappers.CloudModelMapper
|
||||
import org.cryptomator.presentation.ui.activity.view.CloudConnectionListView
|
||||
import org.cryptomator.presentation.workflow.ActivityResult
|
||||
import org.cryptomator.util.crypto.CredentialCryptor
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.inject.Inject
|
||||
@ -34,6 +42,7 @@ import timber.log.Timber
|
||||
@PerView
|
||||
class CloudConnectionListPresenter @Inject constructor( //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val getUsernameUseCase: GetUsernameUseCase, //
|
||||
private val removeCloudUseCase: RemoveCloudUseCase, //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
@ -122,6 +131,18 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
when (selectedCloudType.get()) {
|
||||
CloudTypeModel.WEBDAV -> requestActivityResult(ActivityResultCallbacks.addChangeWebDavCloud(), //
|
||||
Intents.webDavAddOrChangeIntent())
|
||||
CloudTypeModel.PCLOUD -> {
|
||||
val authIntent: Intent = AuthorizationActivity.createIntent(
|
||||
this.context(),
|
||||
AuthorizationRequest.create()
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setClientId("tsAamgqqwk7")
|
||||
.setForceAccessApproval(true)
|
||||
.addPermission("manageshares")
|
||||
.build())
|
||||
requestActivityResult(ActivityResultCallbacks.pCloudAuthenticationFinished(), //
|
||||
authIntent)
|
||||
}
|
||||
CloudTypeModel.LOCAL -> openDocumentTree()
|
||||
}
|
||||
}
|
||||
@ -162,6 +183,77 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
loadCloudList()
|
||||
}
|
||||
|
||||
@Callback
|
||||
fun pCloudAuthenticationFinished(activityResult: ActivityResult?) {
|
||||
val authData: AuthorizationData = AuthorizationActivity.getResult(activityResult!!.intent())
|
||||
val result: AuthorizationResult = authData.result
|
||||
|
||||
when (result) {
|
||||
AuthorizationResult.ACCESS_GRANTED -> {
|
||||
val accessToken: String = CredentialCryptor //
|
||||
.getInstance(this.context()) //
|
||||
.encrypt(authData.token)
|
||||
val pCloudSkeleton: PCloudCloud = PCloudCloud.aPCloudCloud() //
|
||||
.withAccessToken(accessToken)
|
||||
.withUrl(authData.apiHost)
|
||||
.build();
|
||||
getUsernameUseCase //
|
||||
.withCloud(pCloudSkeleton) //
|
||||
.run(object : DefaultResultHandler<String>() {
|
||||
override fun onSuccess(username: String?) {
|
||||
prepareForSavingPCloudCloud(PCloudCloud.aCopyOf(pCloudSkeleton).withUsername(username).build())
|
||||
}
|
||||
})
|
||||
|
||||
Log.d("pCloud", "Account access granted, authData:\n$authData")
|
||||
|
||||
}
|
||||
AuthorizationResult.ACCESS_DENIED -> //TODO: Add proper handling for denied grants.
|
||||
Log.d("pCloud", "Account access denied")
|
||||
AuthorizationResult.AUTH_ERROR -> {
|
||||
//TODO: Add error handling.
|
||||
Log.d("pCloud", """Account access grant error: ${authData.errorMessage}""".trimIndent())
|
||||
}
|
||||
AuthorizationResult.CANCELLED -> {
|
||||
//TODO: Handle cancellation.
|
||||
Log.d("pCloud", "Account access grant cancelled:")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun prepareForSavingPCloudCloud(cloud: PCloudCloud) {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(CloudTypeModel.valueOf(selectedCloudType.get())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
// here check if a cloud with the same mail adress already exists,
|
||||
// if so update (in case of the token changed) else create a new one
|
||||
val existingPCloudCloud: PCloudCloud? = clouds.firstOrNull {
|
||||
(it as PCloudCloud).username() == cloud.username()
|
||||
} as PCloudCloud?
|
||||
|
||||
if (existingPCloudCloud != null && existingPCloudCloud.accessToken() != cloud.accessToken()) {
|
||||
saveCloud(PCloudCloud.aCopyOf(existingPCloudCloud) //
|
||||
.withUrl(cloud.url())
|
||||
.withAccessToken(cloud.accessToken())
|
||||
.build())
|
||||
} else if (existingPCloudCloud == null) {
|
||||
saveCloud(cloud);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun saveCloud(cloud: PCloudCloud) {
|
||||
addOrChangeCloudConnectionUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
fun pickedLocalStorageLocation(result: ActivityResult) {
|
||||
|
@ -2,6 +2,7 @@ package org.cryptomator.presentation.presenter
|
||||
|
||||
import org.cryptomator.domain.Cloud
|
||||
import org.cryptomator.domain.LocalStorageCloud
|
||||
import org.cryptomator.domain.PCloudCloud
|
||||
import org.cryptomator.domain.WebDavCloud
|
||||
import org.cryptomator.domain.di.PerView
|
||||
import org.cryptomator.domain.exception.FatalBackendException
|
||||
@ -16,6 +17,7 @@ import org.cryptomator.presentation.intent.Intents
|
||||
import org.cryptomator.presentation.model.CloudModel
|
||||
import org.cryptomator.presentation.model.CloudTypeModel
|
||||
import org.cryptomator.presentation.model.LocalStorageModel
|
||||
import org.cryptomator.presentation.model.PCloudCloudModel
|
||||
import org.cryptomator.presentation.model.WebDavCloudModel
|
||||
import org.cryptomator.presentation.model.mappers.CloudModelMapper
|
||||
import org.cryptomator.presentation.ui.activity.view.CloudSettingsView
|
||||
@ -34,6 +36,7 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
private val nonSingleLoginClouds: Set<CloudTypeModel> = EnumSet.of( //
|
||||
CloudTypeModel.CRYPTO, //
|
||||
CloudTypeModel.LOCAL, //
|
||||
CloudTypeModel.PCLOUD, //
|
||||
CloudTypeModel.WEBDAV)
|
||||
|
||||
fun loadClouds() {
|
||||
@ -41,7 +44,7 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
}
|
||||
|
||||
fun onCloudClicked(cloudModel: CloudModel) {
|
||||
if (isWebdavOrLocal(cloudModel)) {
|
||||
if (isWebdavOrPCloudOrLocal(cloudModel)) {
|
||||
startConnectionListActivity(cloudModel.cloudType())
|
||||
} else {
|
||||
if (isLoggedIn(cloudModel)) {
|
||||
@ -58,8 +61,8 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWebdavOrLocal(cloudModel: CloudModel): Boolean {
|
||||
return cloudModel is WebDavCloudModel || cloudModel is LocalStorageModel
|
||||
private fun isWebdavOrPCloudOrLocal(cloudModel: CloudModel): Boolean {
|
||||
return cloudModel is WebDavCloudModel || cloudModel is LocalStorageModel || cloudModel is PCloudCloudModel
|
||||
}
|
||||
|
||||
private fun loginCloud(cloudModel: CloudModel) {
|
||||
@ -91,6 +94,7 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
private fun effectiveTitle(cloudTypeModel: CloudTypeModel): String {
|
||||
when (cloudTypeModel) {
|
||||
CloudTypeModel.WEBDAV -> return context().getString(R.string.screen_cloud_settings_webdav_connections)
|
||||
CloudTypeModel.PCLOUD -> return context().getString(R.string.screen_cloud_settings_pcloud_connections)
|
||||
CloudTypeModel.LOCAL -> return context().getString(R.string.screen_cloud_settings_local_storage_locations)
|
||||
}
|
||||
return context().getString(R.string.screen_cloud_settings_title)
|
||||
@ -123,6 +127,7 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
.toMutableList() //
|
||||
.also {
|
||||
it.add(aWebdavCloud())
|
||||
it.add(aPCloudCloud())
|
||||
it.add(aLocalCloud())
|
||||
}
|
||||
view?.render(cloudModel)
|
||||
@ -132,6 +137,10 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
return WebDavCloudModel(WebDavCloud.aWebDavCloudCloud().build())
|
||||
}
|
||||
|
||||
private fun aPCloudCloud(): PCloudCloudModel {
|
||||
return PCloudCloudModel(PCloudCloud.aPCloudCloud().build())
|
||||
}
|
||||
|
||||
private fun aLocalCloud(): CloudModel {
|
||||
return LocalStorageModel(LocalStorageCloud.aLocalStorage().build())
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import org.cryptomator.domain.exception.FatalBackendException
|
||||
import org.cryptomator.presentation.R
|
||||
import org.cryptomator.presentation.model.CloudModel
|
||||
import org.cryptomator.presentation.model.LocalStorageModel
|
||||
import org.cryptomator.presentation.model.PCloudCloudModel
|
||||
import org.cryptomator.presentation.model.WebDavCloudModel
|
||||
import org.cryptomator.presentation.model.comparator.CloudModelComparator
|
||||
import org.cryptomator.presentation.ui.adapter.CloudConnectionListAdapter.CloudConnectionHolder
|
||||
@ -54,6 +55,8 @@ internal constructor(context: Context) : RecyclerViewBaseAdapter<CloudModel, Clo
|
||||
|
||||
if (cloudModel is WebDavCloudModel) {
|
||||
bindWebDavCloudModel(cloudModel)
|
||||
} else if (cloudModel is PCloudCloudModel) {
|
||||
bindPCloudCloudModel(cloudModel)
|
||||
} else if (cloudModel is LocalStorageModel) {
|
||||
bindLocalStorageCloudModel(cloudModel)
|
||||
}
|
||||
@ -70,6 +73,11 @@ internal constructor(context: Context) : RecyclerViewBaseAdapter<CloudModel, Clo
|
||||
|
||||
}
|
||||
|
||||
private fun bindPCloudCloudModel(cloudModel: PCloudCloudModel) {
|
||||
itemView.cloudText.text = cloudModel.username()
|
||||
itemView.cloudSubText.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun bindLocalStorageCloudModel(cloudModel: LocalStorageModel) {
|
||||
if (cloudModel.location().isEmpty()) {
|
||||
itemView.cloudText.text = cloudModel.storage()
|
||||
|
@ -41,6 +41,8 @@ constructor(private val context: Context) : RecyclerViewBaseAdapter<CloudModel,
|
||||
|
||||
if (webdav(cloudModel.cloudType())) {
|
||||
itemView.cloudName.text = context.getString(R.string.screen_cloud_settings_webdav_connections)
|
||||
} else if (pCloud(cloudModel.cloudType())) {
|
||||
itemView.cloudName.text = context.getString(R.string.screen_cloud_settings_pcloud_connections)
|
||||
} else if (local(cloudModel.cloudType())) {
|
||||
itemView.cloudName.text = context.getString(R.string.screen_cloud_settings_local_storage_locations)
|
||||
} else {
|
||||
@ -79,4 +81,8 @@ constructor(private val context: Context) : RecyclerViewBaseAdapter<CloudModel,
|
||||
private fun webdav(cloudType: CloudTypeModel): Boolean {
|
||||
return CloudTypeModel.WEBDAV == cloudType
|
||||
}
|
||||
|
||||
private fun pCloud(cloudType: CloudTypeModel): Boolean {
|
||||
return CloudTypeModel.PCLOUD == cloudType
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,7 @@
|
||||
<string name="screen_settings_background_unlock_preparation_label">Vorbereitungen zum Entsperren im Hintergrund</string>
|
||||
<!-- ## screen: cloud settings -->
|
||||
<string name="screen_cloud_settings_webdav_connections">WebDAV-Verbindungen</string>
|
||||
<string name="screen_cloud_settings_pcloud_connections">pCloud-Verbindungen</string>
|
||||
<string name="screen_cloud_settings_local_storage_locations">Lokale Speicherorte</string>
|
||||
<string name="screen_cloud_settings_log_in_to">Einloggen in</string>
|
||||
<string name="screen_cloud_settings_sign_out_from_cloud">Abmelden von</string>
|
||||
|
@ -110,6 +110,7 @@
|
||||
<string name="screen_settings_section_version">Versión</string>
|
||||
<!-- ## screen: cloud settings -->
|
||||
<string name="screen_cloud_settings_webdav_connections">Conexiones de WebDAV</string>
|
||||
<string name="screen_cloud_settings_pcloud_connections">Conexiones de pCloud</string>
|
||||
<string name="screen_cloud_settings_local_storage_locations">Ubicaciones de almacenamiento local</string>
|
||||
<string name="screen_cloud_settings_log_in_to">Iniciar sesión en</string>
|
||||
<string name="screen_cloud_settings_sign_out_from_cloud">Cerrar sesión de</string>
|
||||
|
@ -173,6 +173,7 @@
|
||||
<string name="screen_settings_background_unlock_preparation_label">Préparations du déverrouillage en arrière-plan</string>
|
||||
<!-- ## screen: cloud settings -->
|
||||
<string name="screen_cloud_settings_webdav_connections">Connexions WebDAV</string>
|
||||
<string name="screen_cloud_settings_pcloud_connections">Connexions pCloud</string>
|
||||
<string name="screen_cloud_settings_local_storage_locations">Emplacements du stockage local</string>
|
||||
<string name="screen_cloud_settings_log_in_to">Se connecter à</string>
|
||||
<string name="screen_cloud_settings_sign_out_from_cloud">Se déconnecter de</string>
|
||||
|
@ -168,6 +168,7 @@
|
||||
<string name="screen_settings_background_unlock_preparation_label">Arka planda kilit açma</string>
|
||||
<!-- ## screen: cloud settings -->
|
||||
<string name="screen_cloud_settings_webdav_connections">WebDAV bağlantıları</string>
|
||||
<string name="screen_cloud_settings_pcloud_connections">pCloud bağlantıları</string>
|
||||
<string name="screen_cloud_settings_local_storage_locations">Yerel depolama konumları</string>
|
||||
<string name="screen_cloud_settings_log_in_to">Giriş</string>
|
||||
<string name="screen_cloud_settings_sign_out_from_cloud">Oturumunu kapat</string>
|
||||
|
@ -254,6 +254,7 @@
|
||||
<!-- ## screen: cloud settings -->
|
||||
<string name="screen_cloud_settings_title">@string/screen_settings_cloud_settings_label</string>
|
||||
<string name="screen_cloud_settings_webdav_connections">WebDAV connections</string>
|
||||
<string name="screen_cloud_settings_pcloud_connections">pCloud connections</string>
|
||||
<string name="screen_cloud_settings_local_storage_locations">Local storage locations</string>
|
||||
<string name="screen_cloud_settings_log_in_to">Log in to</string>
|
||||
<string name="screen_cloud_settings_sign_out_from_cloud">Sign out from</string>
|
||||
|
@ -34,6 +34,7 @@ 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.PCloudCloudModel
|
||||
import org.cryptomator.presentation.model.ProgressModel
|
||||
import org.cryptomator.presentation.model.ProgressStateModel
|
||||
import org.cryptomator.presentation.model.WebDavCloudModel
|
||||
@ -65,6 +66,7 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
DropboxAuthStrategy(), //
|
||||
GoogleDriveAuthStrategy(), //
|
||||
OnedriveAuthStrategy(), //
|
||||
PCloudAuthStrategy(), //
|
||||
WebDAVAuthStrategy(), //
|
||||
LocalStorageAuthStrategy() //
|
||||
)
|
||||
@ -282,6 +284,26 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
}
|
||||
}
|
||||
|
||||
private inner class PCloudAuthStrategy : AuthStrategy {
|
||||
|
||||
override fun supports(cloud: CloudModel): Boolean {
|
||||
return cloud.cloudType() == CloudTypeModel.PCLOUD
|
||||
}
|
||||
|
||||
override fun resumed(intent: AuthenticateCloudIntent) {
|
||||
handlePCloudAuthenticationExceptionIfRequired(intent.cloud() as PCloudCloudModel, intent.error())
|
||||
}
|
||||
|
||||
private fun handlePCloudAuthenticationExceptionIfRequired(cloud: PCloudCloudModel, e: AuthenticationException) {
|
||||
Timber.tag("AuthicateCloudPrester").e(e)
|
||||
when {
|
||||
ExceptionUtil.contains(e, WrongCredentialsException::class.java) -> {
|
||||
failAuthentication(cloud.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class WebDAVAuthStrategy : AuthStrategy {
|
||||
|
||||
override fun supports(cloud: CloudModel): Boolean {
|
||||
|
Loading…
x
Reference in New Issue
Block a user