Merge pull request #1281 from vector-im/feature/various_issues_verification_ssss_bootstrap
Feature/various issues verification ssss bootstrap
This commit is contained in:
commit
4e3df99e42
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.api.failure
|
package im.vector.matrix.android.api.failure
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.extensions.tryThis
|
||||||
|
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
||||||
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
import javax.net.ssl.HttpsURLConnection
|
import javax.net.ssl.HttpsURLConnection
|
||||||
|
|
||||||
fun Throwable.is401() =
|
fun Throwable.is401() =
|
||||||
|
@ -37,3 +40,18 @@ fun Throwable.isInvalidPassword(): Boolean {
|
||||||
&& error.code == MatrixError.M_FORBIDDEN
|
&& error.code == MatrixError.M_FORBIDDEN
|
||||||
&& error.message == "Invalid password"
|
&& error.message == "Invalid password"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
|
||||||
|
*/
|
||||||
|
fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
|
||||||
|
return if (this is Failure.OtherServerError && this.httpCode == 401) {
|
||||||
|
tryThis {
|
||||||
|
MoshiProvider.providesMoshi()
|
||||||
|
.adapter(RegistrationFlowResponse::class.java)
|
||||||
|
.fromJson(this.errorBody)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ package im.vector.matrix.android.internal.auth.registration
|
||||||
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.internal.auth.AuthAPI
|
import im.vector.matrix.android.internal.auth.AuthAPI
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
|
||||||
|
@ -39,25 +39,9 @@ internal class DefaultRegisterTask(
|
||||||
apiCall = authAPI.register(params.registrationParams)
|
apiCall = authAPI.register(params.registrationParams)
|
||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (throwable is Failure.OtherServerError && throwable.httpCode == 401) {
|
throw throwable.toRegistrationFlowResponse()
|
||||||
// Parse to get a RegistrationFlowResponse
|
?.let { Failure.RegistrationFlowError(it) }
|
||||||
val registrationFlowResponse = try {
|
?: throwable
|
||||||
MoshiProvider.providesMoshi()
|
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
|
||||||
.fromJson(throwable.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
// check if the server response can be cast
|
|
||||||
if (registrationFlowResponse != null) {
|
|
||||||
throw Failure.RegistrationFlowError(registrationFlowResponse)
|
|
||||||
} else {
|
|
||||||
throw throwable
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Other error
|
|
||||||
throw throwable
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
package im.vector.matrix.android.internal.crypto.tasks
|
package im.vector.matrix.android.internal.crypto.tasks
|
||||||
|
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams
|
import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
@ -43,25 +42,9 @@ internal class DefaultDeleteDeviceTask @Inject constructor(
|
||||||
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams())
|
apiCall = cryptoApi.deleteDevice(params.deviceId, DeleteDeviceParams())
|
||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (throwable is Failure.OtherServerError && throwable.httpCode == 401) {
|
throw throwable.toRegistrationFlowResponse()
|
||||||
// Parse to get a RegistrationFlowResponse
|
?.let { Failure.RegistrationFlowError(it) }
|
||||||
val registrationFlowResponse = try {
|
?: throwable
|
||||||
MoshiProvider.providesMoshi()
|
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
|
||||||
.fromJson(throwable.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
// check if the server response can be casted
|
|
||||||
if (registrationFlowResponse != null) {
|
|
||||||
throw Failure.RegistrationFlowError(registrationFlowResponse)
|
|
||||||
} else {
|
|
||||||
throw throwable
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Other error
|
|
||||||
throw throwable
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,13 @@
|
||||||
package im.vector.matrix.android.internal.crypto.tasks
|
package im.vector.matrix.android.internal.crypto.tasks
|
||||||
|
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
||||||
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
|
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse
|
import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.UploadSigningKeysBody
|
import im.vector.matrix.android.internal.crypto.model.rest.UploadSigningKeysBody
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
||||||
import im.vector.matrix.android.internal.crypto.model.toRest
|
import im.vector.matrix.android.internal.crypto.model.toRest
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
@ -65,37 +64,25 @@ internal class DefaultUploadSigningKeysTask @Inject constructor(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (throwable is Failure.OtherServerError
|
val registrationFlowResponse = throwable.toRegistrationFlowResponse()
|
||||||
&& throwable.httpCode == 401
|
if (registrationFlowResponse != null
|
||||||
&& params.userPasswordAuth != null
|
&& params.userPasswordAuth != null
|
||||||
/* Avoid infinite loop */
|
/* Avoid infinite loop */
|
||||||
&& params.userPasswordAuth.session.isNullOrEmpty()
|
&& params.userPasswordAuth.session.isNullOrEmpty()
|
||||||
) {
|
) {
|
||||||
try {
|
|
||||||
MoshiProvider.providesMoshi()
|
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
|
||||||
.fromJson(throwable.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}?.let {
|
|
||||||
// Retry with authentication
|
// Retry with authentication
|
||||||
try {
|
|
||||||
val req = executeRequest<KeysQueryResponse>(eventBus) {
|
val req = executeRequest<KeysQueryResponse>(eventBus) {
|
||||||
apiCall = cryptoApi.uploadSigningKeys(
|
apiCall = cryptoApi.uploadSigningKeys(
|
||||||
uploadQuery.copy(auth = params.userPasswordAuth.copy(session = it.session))
|
uploadQuery.copy(auth = params.userPasswordAuth.copy(session = registrationFlowResponse.session))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (req.failures?.isNotEmpty() == true) {
|
if (req.failures?.isNotEmpty() == true) {
|
||||||
throw UploadSigningKeys(req.failures)
|
throw UploadSigningKeys(req.failures)
|
||||||
}
|
}
|
||||||
return
|
} else {
|
||||||
} catch (failure: Throwable) {
|
|
||||||
throw failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Other error
|
// Other error
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.session.account
|
package im.vector.matrix.android.internal.session.account
|
||||||
|
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.android.internal.di.UserId
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
@ -45,31 +43,20 @@ internal class DefaultChangePasswordTask @Inject constructor(
|
||||||
apiCall = accountAPI.changePassword(changePasswordParams)
|
apiCall = accountAPI.changePassword(changePasswordParams)
|
||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
if (throwable is Failure.OtherServerError
|
val registrationFlowResponse = throwable.toRegistrationFlowResponse()
|
||||||
&& throwable.httpCode == 401
|
|
||||||
|
if (registrationFlowResponse != null
|
||||||
/* Avoid infinite loop */
|
/* Avoid infinite loop */
|
||||||
&& changePasswordParams.auth?.session == null) {
|
&& changePasswordParams.auth?.session == null) {
|
||||||
try {
|
|
||||||
MoshiProvider.providesMoshi()
|
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
|
||||||
.fromJson(throwable.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}?.let {
|
|
||||||
// Retry with authentication
|
// Retry with authentication
|
||||||
try {
|
|
||||||
executeRequest<Unit>(eventBus) {
|
executeRequest<Unit>(eventBus) {
|
||||||
apiCall = accountAPI.changePassword(
|
apiCall = accountAPI.changePassword(
|
||||||
changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = it.session))
|
changePasswordParams.copy(auth = changePasswordParams.auth?.copy(session = registrationFlowResponse.session))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return
|
} else {
|
||||||
} catch (failure: Throwable) {
|
|
||||||
throw failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw throwable
|
throw throwable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -95,6 +95,14 @@ class BootstrapConfirmPassphraseFragment @Inject constructor(
|
||||||
sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
|
sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
|
bootstrapSubmit.clicks()
|
||||||
|
.debounce(300, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe {
|
||||||
|
submit()
|
||||||
|
}
|
||||||
|
.disposeOnDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun submit() = withState(sharedViewModel) { state ->
|
private fun submit() = withState(sharedViewModel) { state ->
|
||||||
|
@ -113,8 +121,6 @@ class BootstrapConfirmPassphraseFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
super.invalidate()
|
|
||||||
|
|
||||||
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.crypto.recover
|
||||||
|
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.api.failure.MatrixError
|
import im.vector.matrix.android.api.failure.MatrixError
|
||||||
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
||||||
|
@ -28,13 +29,11 @@ import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageSer
|
||||||
import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo
|
import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo
|
||||||
import im.vector.matrix.android.api.session.securestorage.SsssKeySpec
|
import im.vector.matrix.android.api.session.securestorage.SsssKeySpec
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
|
||||||
import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding
|
import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
|
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
|
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
|
||||||
import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
|
import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.android.internal.util.awaitCallback
|
import im.vector.matrix.android.internal.util.awaitCallback
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.platform.ViewModelTask
|
import im.vector.riotx.core.platform.ViewModelTask
|
||||||
|
@ -230,15 +229,10 @@ class BootstrapCrossSigningTask @Inject constructor(
|
||||||
private fun handleInitializeXSigningError(failure: Throwable): BootstrapResult {
|
private fun handleInitializeXSigningError(failure: Throwable): BootstrapResult {
|
||||||
if (failure is Failure.ServerError && failure.error.code == MatrixError.M_FORBIDDEN) {
|
if (failure is Failure.ServerError && failure.error.code == MatrixError.M_FORBIDDEN) {
|
||||||
return BootstrapResult.InvalidPasswordError(failure.error)
|
return BootstrapResult.InvalidPasswordError(failure.error)
|
||||||
} else if (failure is Failure.OtherServerError && failure.httpCode == 401) {
|
} else {
|
||||||
try {
|
val registrationFlowResponse = failure.toRegistrationFlowResponse()
|
||||||
MoshiProvider.providesMoshi()
|
if (registrationFlowResponse != null) {
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
if (registrationFlowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } != true) {
|
||||||
.fromJson(failure.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}?.let { flowResponse ->
|
|
||||||
if (flowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } != true) {
|
|
||||||
// can't do this from here
|
// can't do this from here
|
||||||
return BootstrapResult.UnsupportedAuthFlow()
|
return BootstrapResult.UnsupportedAuthFlow()
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,14 @@ class BootstrapEnterPassphraseFragment @Inject constructor(
|
||||||
sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
|
sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
|
bootstrapSubmit.clicks()
|
||||||
|
.debounce(300, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe {
|
||||||
|
submit()
|
||||||
|
}
|
||||||
|
.disposeOnDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun submit() = withState(sharedViewModel) { state ->
|
private fun submit() = withState(sharedViewModel) { state ->
|
||||||
|
@ -108,8 +116,6 @@ class BootstrapEnterPassphraseFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
super.invalidate()
|
|
||||||
|
|
||||||
if (state.step is BootstrapStep.SetupPassphrase) {
|
if (state.step is BootstrapStep.SetupPassphrase) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
|
|
|
@ -167,6 +167,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
val crossSigningEnabledOnAccount = myCrossSigningKeys != null
|
val crossSigningEnabledOnAccount = myCrossSigningKeys != null
|
||||||
|
|
||||||
if (!crossSigningEnabledOnAccount && !sharedActionViewModel.isAccountCreation) {
|
if (!crossSigningEnabledOnAccount && !sharedActionViewModel.isAccountCreation) {
|
||||||
|
// Do not propose for SSO accounts, because we do not support yet confirming account credentials using SSO
|
||||||
|
if (session.getHomeServerCapabilities().canChangePassword) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
session,
|
session,
|
||||||
|
@ -175,6 +177,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
) {
|
) {
|
||||||
it.navigator.upgradeSessionSecurity(it)
|
it.navigator.upgradeSessionSecurity(it)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Do not do it again
|
||||||
|
sharedActionViewModel.hasDisplayedCompleteSecurityPrompt = true
|
||||||
|
}
|
||||||
} else if (myCrossSigningKeys?.isTrusted() == false) {
|
} else if (myCrossSigningKeys?.isTrusted() == false) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
|
|
|
@ -37,7 +37,6 @@ class CrossSigningEpoxyController @Inject constructor(
|
||||||
|
|
||||||
interface InteractionListener {
|
interface InteractionListener {
|
||||||
fun onInitializeCrossSigningKeys()
|
fun onInitializeCrossSigningKeys()
|
||||||
fun onResetCrossSigningKeys()
|
|
||||||
fun verifySession()
|
fun verifySession()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,18 +50,6 @@ class CrossSigningEpoxyController @Inject constructor(
|
||||||
titleIconResourceId(R.drawable.ic_shield_trusted)
|
titleIconResourceId(R.drawable.ic_shield_trusted)
|
||||||
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete))
|
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_complete))
|
||||||
}
|
}
|
||||||
if (vectorPreferences.developerMode() && !data.isUploadingKeys) {
|
|
||||||
bottomSheetVerificationActionItem {
|
|
||||||
id("resetkeys")
|
|
||||||
title("Reset keys")
|
|
||||||
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
|
||||||
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
listener {
|
|
||||||
interactionListener?.onResetCrossSigningKeys()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (data.xSigningKeysAreTrusted) {
|
} else if (data.xSigningKeysAreTrusted) {
|
||||||
genericItem {
|
genericItem {
|
||||||
id("trusted")
|
id("trusted")
|
||||||
|
@ -70,19 +57,6 @@ class CrossSigningEpoxyController @Inject constructor(
|
||||||
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted))
|
title(stringProvider.getString(R.string.encryption_information_dg_xsigning_trusted))
|
||||||
}
|
}
|
||||||
if (!data.isUploadingKeys) {
|
if (!data.isUploadingKeys) {
|
||||||
if (vectorPreferences.developerMode()) {
|
|
||||||
bottomSheetVerificationActionItem {
|
|
||||||
id("resetkeys")
|
|
||||||
title("Reset keys")
|
|
||||||
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
|
||||||
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
listener {
|
|
||||||
interactionListener?.onResetCrossSigningKeys()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bottomSheetVerificationActionItem {
|
bottomSheetVerificationActionItem {
|
||||||
id("verify")
|
id("verify")
|
||||||
title(stringProvider.getString(R.string.complete_security))
|
title(stringProvider.getString(R.string.complete_security))
|
||||||
|
@ -110,18 +84,6 @@ class CrossSigningEpoxyController @Inject constructor(
|
||||||
interactionListener?.verifySession()
|
interactionListener?.verifySession()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vectorPreferences.developerMode()) {
|
|
||||||
bottomSheetVerificationActionItem {
|
|
||||||
id("resetkeys")
|
|
||||||
title("Reset keys")
|
|
||||||
titleColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
|
||||||
iconColor(colorProvider.getColor(R.color.riotx_destructive_accent))
|
|
||||||
listener {
|
|
||||||
interactionListener?.onResetCrossSigningKeys()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
genericItem {
|
genericItem {
|
||||||
id("not")
|
id("not")
|
||||||
|
@ -130,7 +92,7 @@ class CrossSigningEpoxyController @Inject constructor(
|
||||||
if (vectorPreferences.developerMode() && !data.isUploadingKeys) {
|
if (vectorPreferences.developerMode() && !data.isUploadingKeys) {
|
||||||
bottomSheetVerificationActionItem {
|
bottomSheetVerificationActionItem {
|
||||||
id("initKeys")
|
id("initKeys")
|
||||||
title("Initialize keys")
|
title(stringProvider.getString(R.string.initialize_cross_signing))
|
||||||
titleColor(colorProvider.getColor(R.color.riotx_positive_accent))
|
titleColor(colorProvider.getColor(R.color.riotx_positive_accent))
|
||||||
iconRes(R.drawable.ic_arrow_right)
|
iconRes(R.drawable.ic_arrow_right)
|
||||||
iconColor(colorProvider.getColor(R.color.riotx_positive_accent))
|
iconColor(colorProvider.getColor(R.color.riotx_positive_accent))
|
||||||
|
|
|
@ -101,14 +101,4 @@ class CrossSigningSettingsFragment @Inject constructor(
|
||||||
override fun verifySession() {
|
override fun verifySession() {
|
||||||
viewModel.handle(CrossSigningAction.VerifySession)
|
viewModel.handle(CrossSigningAction.VerifySession)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResetCrossSigningKeys() {
|
|
||||||
AlertDialog.Builder(requireContext())
|
|
||||||
.setTitle(R.string.dialog_title_confirmation)
|
|
||||||
.setMessage(R.string.are_you_sure)
|
|
||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
|
||||||
viewModel.handle(CrossSigningAction.InitializeCrossSigning)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,12 @@ import com.airbnb.mvrx.ViewModelContext
|
||||||
import com.squareup.inject.assisted.Assisted
|
import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.toRegistrationFlowResponse
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||||
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
|
|
||||||
import im.vector.matrix.android.internal.crypto.crosssigning.isVerified
|
import im.vector.matrix.android.internal.crypto.crosssigning.isVerified
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotx.core.extensions.exhaustive
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
@ -113,19 +111,12 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
_pendingSession = null
|
_pendingSession = null
|
||||||
|
|
||||||
if (failure is Failure.OtherServerError && failure.httpCode == 401) {
|
val registrationFlowResponse = failure.toRegistrationFlowResponse()
|
||||||
try {
|
if (registrationFlowResponse != null) {
|
||||||
MoshiProvider.providesMoshi()
|
|
||||||
.adapter(RegistrationFlowResponse::class.java)
|
|
||||||
.fromJson(failure.errorBody)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}?.let { flowResponse ->
|
|
||||||
// Retry with authentication
|
// Retry with authentication
|
||||||
if (flowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) {
|
if (registrationFlowResponse.flows?.any { it.stages?.contains(LoginFlowTypes.PASSWORD) == true } == true) {
|
||||||
_pendingSession = flowResponse.session ?: ""
|
_pendingSession = registrationFlowResponse.session ?: ""
|
||||||
_viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword)
|
_viewEvents.post(CrossSigningSettingsViewEvents.RequestPassword)
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
// can't do this from here
|
// can't do this from here
|
||||||
_viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile")))
|
_viewEvents.post(CrossSigningSettingsViewEvents.Failure(Throwable("You cannot do that from mobile")))
|
||||||
|
@ -133,17 +124,15 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(@Assisted privat
|
||||||
setState {
|
setState {
|
||||||
copy(isUploadingKeys = false)
|
copy(isUploadingKeys = false)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
_viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure))
|
_viewEvents.post(CrossSigningSettingsViewEvents.Failure(failure))
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(isUploadingKeys = false)
|
copy(isUploadingKeys = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -12,10 +11,9 @@
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="16dp"
|
android:paddingTop="16dp"
|
||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp">
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/bootstrapIcon"
|
android:id="@+id/bootstrapIcon"
|
||||||
|
@ -28,23 +26,19 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/bootstrapTitleText"
|
android:id="@+id/bootstrapTitleText"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_weight="1"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/bootstrapIcon"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/bootstrapIcon"
|
app:layout_constraintStart_toEndOf="@+id/bootstrapIcon"
|
||||||
app:layout_constraintTop_toTopOf="@+id/bootstrapIcon"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@string/recovery_passphrase" />
|
tools:text="@string/recovery_passphrase" />
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
|
|
@ -44,13 +44,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_weight="1"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/verificationRequestAvatar"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/verificationRequestAvatar"
|
app:layout_constraintStart_toEndOf="@+id/verificationRequestAvatar"
|
||||||
app:layout_constraintTop_toTopOf="@+id/verificationRequestAvatar"
|
app:layout_constraintTop_toTopOf="@+id/verificationRequestAvatar"
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
tools:text="@string/enter_account_password"
|
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/bootstrapAccountPasswordTil"
|
app:layout_constraintBottom_toTopOf="@id/bootstrapAccountPasswordTil"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@string/enter_account_password" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/bootstrapAccountPasswordTil"
|
android:id="@+id/bootstrapAccountPasswordTil"
|
||||||
|
@ -59,9 +59,7 @@
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/bootstrapPasswordButton"
|
android:id="@+id/bootstrapPasswordButton"
|
||||||
style="@style/VectorButtonStyleText"
|
style="@style/VectorButtonStyleText"
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||||
android:padding="8dp"
|
|
||||||
android:text="@string/_continue"
|
android:text="@string/_continue"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:errorEnabled="true"
|
app:errorEnabled="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/ssss_view_show_password"
|
app:layout_constraintEnd_toStartOf="@id/ssss_view_show_password"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText">
|
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText">
|
||||||
|
@ -34,11 +32,11 @@
|
||||||
android:id="@+id/ssss_passphrase_enter_edittext"
|
android:id="@+id/ssss_passphrase_enter_edittext"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:hint="@string/passphrase_enter_passphrase"
|
|
||||||
android:imeOptions="actionDone"
|
android:imeOptions="actionDone"
|
||||||
android:maxLines="3"
|
android:maxLines="3"
|
||||||
android:singleLine="false"
|
android:singleLine="false"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
|
tools:hint="@string/passphrase_enter_passphrase"
|
||||||
tools:inputType="textPassword" />
|
tools:inputType="textPassword" />
|
||||||
|
|
||||||
<!-- This is inside the TIL, if not the keyboard will hide it when in bottomsheet -->
|
<!-- This is inside the TIL, if not the keyboard will hide it when in bottomsheet -->
|
||||||
|
@ -46,9 +44,9 @@
|
||||||
<im.vector.riotx.core.ui.views.PasswordStrengthBar
|
<im.vector.riotx.core.ui.views.PasswordStrengthBar
|
||||||
android:id="@+id/ssss_passphrase_security_progress"
|
android:id="@+id/ssss_passphrase_security_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_marginBottom="2dp"
|
android:layout_height="4dp"
|
||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:layout_height="4dp" />
|
android:layout_marginBottom="2dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/bootstrapWarningInfo"
|
android:id="@+id/bootstrapWarningInfo"
|
||||||
|
@ -56,12 +54,12 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:textSize="12sp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:drawableStart="@drawable/ic_alert_triangle"
|
android:drawableStart="@drawable/ic_alert_triangle"
|
||||||
android:drawableTint="@color/riotx_destructive_accent"
|
|
||||||
android:drawablePadding="4dp"
|
android:drawablePadding="4dp"
|
||||||
android:text="@string/bootstrap_dont_reuse_pwd" />
|
android:drawableTint="@color/riotx_destructive_accent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/bootstrap_dont_reuse_pwd"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
@ -78,6 +76,13 @@
|
||||||
app:layout_constraintStart_toEndOf="@+id/ssss_passphrase_enter_til"
|
app:layout_constraintStart_toEndOf="@+id/ssss_passphrase_enter_til"
|
||||||
app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til" />
|
app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/bootstrapSubmit"
|
||||||
|
style="@style/VectorButtonStyleText"
|
||||||
|
android:text="@string/_continue"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/ssss_passphrase_enter_til" />
|
||||||
|
|
||||||
<!-- <TextView-->
|
<!-- <TextView-->
|
||||||
<!-- android:id="@+id/bootstrapWarningInfo"-->
|
<!-- android:id="@+id/bootstrapWarningInfo"-->
|
||||||
|
|
|
@ -79,7 +79,6 @@
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/bootstrapMigrateContinueButton"
|
android:id="@+id/bootstrapMigrateContinueButton"
|
||||||
style="@style/VectorButtonStyleText"
|
style="@style/VectorButtonStyleText"
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||||
android:text="@string/_continue"
|
android:text="@string/_continue"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
Loading…
Reference in New Issue