Secure secrets passed to intent

This commit is contained in:
Valere 2021-02-02 08:59:28 +01:00
parent 76b425ee8a
commit 6c9b16088f
7 changed files with 36 additions and 14 deletions

View File

@ -49,7 +49,8 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
val flowType: String?, val flowType: String?,
val title: String?, val title: String?,
val session: String?, val session: String?,
val lastErrorCode: String? val lastErrorCode: String?,
val resultKeyStoreAlias: String
) : Parcelable ) : Parcelable
// For sso // For sso
@ -101,7 +102,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
is ReAuthEvents.PasswordFinishSuccess -> { is ReAuthEvents.PasswordFinishSuccess -> {
setResult(RESULT_OK, Intent().apply { setResult(RESULT_OK, Intent().apply {
putExtra(RESULT_FLOW_TYPE, LoginFlowTypes.PASSWORD) putExtra(RESULT_FLOW_TYPE, LoginFlowTypes.PASSWORD)
putExtra(RESULT_VALUE, it.password) putExtra(RESULT_VALUE, it.passwordSafeForIntent)
}) })
finish() finish()
} }
@ -197,8 +198,13 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
const val EXTRA_REASON_TITLE = "EXTRA_REASON_TITLE" const val EXTRA_REASON_TITLE = "EXTRA_REASON_TITLE"
const val RESULT_FLOW_TYPE = "RESULT_FLOW_TYPE" const val RESULT_FLOW_TYPE = "RESULT_FLOW_TYPE"
const val RESULT_VALUE = "RESULT_VALUE" const val RESULT_VALUE = "RESULT_VALUE"
const val DEFAULT_RESULT_KEYSTORE_ALIAS = "ReAuthActivity"
fun newIntent(context: Context, fromError: RegistrationFlowResponse, lastErrorCode: String?, reasonTitle: String?): Intent { fun newIntent(context: Context,
fromError: RegistrationFlowResponse,
lastErrorCode: String?,
reasonTitle: String?,
resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent {
val authType = when (fromError.nextUncompletedStage()) { val authType = when (fromError.nextUncompletedStage()) {
LoginFlowTypes.PASSWORD -> { LoginFlowTypes.PASSWORD -> {
LoginFlowTypes.PASSWORD LoginFlowTypes.PASSWORD
@ -212,7 +218,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
} }
} }
return Intent(context, ReAuthActivity::class.java).apply { return Intent(context, ReAuthActivity::class.java).apply {
putExtra(MvRx.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode)) putExtra(MvRx.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode, resultKeyStoreAlias))
} }
} }
} }

View File

@ -21,5 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents
sealed class ReAuthEvents : VectorViewEvents { sealed class ReAuthEvents : VectorViewEvents {
data class OpenSsoURl(val url: String) : ReAuthEvents() data class OpenSsoURl(val url: String) : ReAuthEvents()
object Dismiss : ReAuthEvents() object Dismiss : ReAuthEvents()
data class PasswordFinishSuccess(val password: String) : ReAuthEvents() data class PasswordFinishSuccess(val passwordSafeForIntent: String) : ReAuthEvents()
} }

View File

@ -24,13 +24,15 @@ data class ReAuthState(
val flowType: String? = null, val flowType: String? = null,
val ssoFallbackPageWasShown: Boolean = false, val ssoFallbackPageWasShown: Boolean = false,
val passwordVisible: Boolean = false, val passwordVisible: Boolean = false,
val lastErrorCode: String? = null val lastErrorCode: String? = null,
val resultKeyStoreAlias: String = ""
) : MvRxState { ) : MvRxState {
constructor(args: ReAuthActivity.Args) : this( constructor(args: ReAuthActivity.Args) : this(
args.title, args.title,
args.session, args.session,
args.flowType, args.flowType,
lastErrorCode = args.lastErrorCode lastErrorCode = args.lastErrorCode,
resultKeyStoreAlias = args.resultKeyStoreAlias
) )
constructor() : this(null, null) constructor() : this(null, null)

View File

@ -24,14 +24,14 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
import java.io.ByteArrayOutputStream
class ReAuthViewModel @AssistedInject constructor( class ReAuthViewModel @AssistedInject constructor(
@Assisted val initialState: ReAuthState, @Assisted val initialState: ReAuthState,
private val session: Session, private val session: Session
private val authenticationService: AuthenticationService
) : VectorViewModel<ReAuthState, ReAuthActions, ReAuthEvents>(initialState) { ) : VectorViewModel<ReAuthState, ReAuthActions, ReAuthEvents>(initialState) {
@AssistedFactory @AssistedFactory
@ -72,7 +72,12 @@ class ReAuthViewModel @AssistedInject constructor(
} }
} }
is ReAuthActions.ReAuthWithPass -> { is ReAuthActions.ReAuthWithPass -> {
_viewEvents.post(ReAuthEvents.PasswordFinishSuccess(action.password)) val safeForIntentCypher = ByteArrayOutputStream().also {
it.use {
session.securelyStoreObject(action.password, initialState.resultKeyStoreAlias, it)
}
}.toByteArray().toBase64NoPadding()
_viewEvents.post(ReAuthEvents.PasswordFinishSuccess(safeForIntentCypher))
} }
} }
} }

View File

@ -34,6 +34,7 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.platform.WaitingViewData
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -44,6 +45,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
@ -269,10 +271,11 @@ class BootstrapSharedViewModel @AssistedInject constructor(
uiaContinuation?.resume(DefaultBaseAuth(session = pendingAuth?.session ?: "")) uiaContinuation?.resume(DefaultBaseAuth(session = pendingAuth?.session ?: ""))
} }
is BootstrapActions.PasswordAuthDone -> { is BootstrapActions.PasswordAuthDone -> {
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
uiaContinuation?.resume( uiaContinuation?.resume(
UserPasswordAuth( UserPasswordAuth(
session = pendingAuth?.session, session = pendingAuth?.session,
password = action.password, password = decryptedPass,
user = session.myUserId user = session.myUserId
) )
) )

View File

@ -26,6 +26,7 @@ import im.vector.app.R
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction import io.reactivex.functions.BiFunction
@ -38,6 +39,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
@ -134,10 +136,11 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
Unit Unit
} }
is CrossSigningSettingsAction.PasswordAuthDone -> { is CrossSigningSettingsAction.PasswordAuthDone -> {
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
uiaContinuation?.resume( uiaContinuation?.resume(
UserPasswordAuth( UserPasswordAuth(
session = pendingAuth?.session, session = pendingAuth?.session,
password = action.password, password = decryptedPass,
user = session.myUserId user = session.myUserId
) )
) )

View File

@ -32,6 +32,7 @@ import dagger.assisted.AssistedInject
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction import io.reactivex.functions.BiFunction
@ -51,6 +52,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
@ -221,10 +223,11 @@ class DevicesViewModel @AssistedInject constructor(
Unit Unit
} }
is DevicesAction.PasswordAuthDone -> { is DevicesAction.PasswordAuthDone -> {
val decryptedPass = session.loadSecureSecret<String>(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS)
uiaContinuation?.resume( uiaContinuation?.resume(
UserPasswordAuth( UserPasswordAuth(
session = pendingAuth?.session, session = pendingAuth?.session,
password = action.password, password = decryptedPass,
user = session.myUserId user = session.myUserId
) )
) )