diff --git a/changelog.d/5398.bugfix b/changelog.d/5398.bugfix new file mode 100644 index 0000000000..24da1952b3 --- /dev/null +++ b/changelog.d/5398.bugfix @@ -0,0 +1 @@ +Adds LoginType to SessionParams to fix soft logout form not showing for SSO and Password type diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt new file mode 100644 index 0000000000..627a825679 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/LoginType.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.auth + +enum class LoginType { + PASSWORD, + SSO, + UNSUPPORTED, + CUSTOM, + DIRECT, + UNKNOWN; + + companion object { + + fun fromName(name: String) = when (name) { + PASSWORD.name -> PASSWORD + SSO.name -> SSO + UNSUPPORTED.name -> UNSUPPORTED + CUSTOM.name -> CUSTOM + DIRECT.name -> DIRECT + else -> UNKNOWN + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt index e3815231d9..de227631ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.auth.data +import org.matrix.android.sdk.api.auth.LoginType + /** * This data class holds necessary data to open a session. * You don't have to manually instantiate it. @@ -34,7 +36,12 @@ data class SessionParams( /** * Set to false if the current token is not valid anymore. Application should not have to use this info. */ - val isTokenValid: Boolean + val isTokenValid: Boolean, + + /** + * The authentication method that was used to create the session. + */ + val loginType: LoginType, ) { /* * Shortcuts. Usually the application should only need to use these shortcuts diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt index ddb70be906..463692e574 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt @@ -83,6 +83,9 @@ internal abstract class AuthModule { @Binds abstract fun bindSessionCreator(creator: DefaultSessionCreator): SessionCreator + @Binds + abstract fun bindSessionParamsCreator(creator: DefaultSessionParamsCreator): SessionParamsCreator + @Binds abstract fun bindDirectLoginTask(task: DefaultDirectLoginTask): DirectLoginTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index 9d6b018a67..446f931847 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -22,6 +22,7 @@ import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.data.LoginFlowResult @@ -361,7 +362,7 @@ internal class DefaultAuthenticationService @Inject constructor( homeServerConnectionConfig: HomeServerConnectionConfig, credentials: Credentials ): Session { - return sessionCreator.createSession(credentials, homeServerConnectionConfig) + return sessionCreator.createSession(credentials, homeServerConnectionConfig, LoginType.SSO) } override suspend fun getWellKnownData( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt index ba01146a4a..7dbb11c7fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt @@ -16,69 +16,41 @@ package org.matrix.android.sdk.internal.auth -import android.net.Uri +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig -import org.matrix.android.sdk.api.auth.data.SessionParams -import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.internal.SessionManager -import timber.log.Timber import javax.inject.Inject internal interface SessionCreator { - suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session + + suspend fun createSession( + credentials: Credentials, + homeServerConnectionConfig: HomeServerConnectionConfig, + loginType: LoginType, + ): Session } internal class DefaultSessionCreator @Inject constructor( private val sessionParamsStore: SessionParamsStore, private val sessionManager: SessionManager, private val pendingSessionStore: PendingSessionStore, - private val isValidClientServerApiTask: IsValidClientServerApiTask + private val sessionParamsCreator: SessionParamsCreator, ) : SessionCreator { /** * Credentials can affect the homeServerConnectionConfig, override homeserver url and/or * identity server url if provided in the credentials. */ - override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session { + override suspend fun createSession( + credentials: Credentials, + homeServerConnectionConfig: HomeServerConnectionConfig, + loginType: LoginType, + ): Session { // We can cleanup the pending session params pendingSessionStore.delete() - - val overriddenUrl = credentials.discoveryInformation?.homeServer?.baseURL - // remove trailing "/" - ?.trim { it == '/' } - ?.takeIf { it.isNotBlank() } - // It can be the same value, so in this case, do not check again the validity - ?.takeIf { it != homeServerConnectionConfig.homeServerUriBase.toString() } - ?.also { Timber.d("Overriding homeserver url to $it (will check if valid)") } - ?.let { Uri.parse(it) } - ?.takeIf { - // Validate the URL, if the configuration is wrong server side, do not override - tryOrNull { - isValidClientServerApiTask.execute( - IsValidClientServerApiTask.Params( - homeServerConnectionConfig.copy(homeServerUriBase = it) - ) - ) - .also { Timber.d("Overriding homeserver url: $it") } - } ?: true // In case of other error (no network, etc.), consider it is valid... - } - - val sessionParams = SessionParams( - credentials = credentials, - homeServerConnectionConfig = homeServerConnectionConfig.copy( - homeServerUriBase = overriddenUrl ?: homeServerConnectionConfig.homeServerUriBase, - identityServerUri = credentials.discoveryInformation?.identityServer?.baseURL - // remove trailing "/" - ?.trim { it == '/' } - ?.takeIf { it.isNotBlank() } - ?.also { Timber.d("Overriding identity server url to $it") } - ?.let { Uri.parse(it) } - ?: homeServerConnectionConfig.identityServerUri - ), - isTokenValid = true) - + val sessionParams = sessionParamsCreator.create(credentials, homeServerConnectionConfig, loginType) sessionParamsStore.save(sessionParams) return sessionManager.getOrCreateSession(sessionParams) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt new file mode 100644 index 0000000000..31ed9a1e85 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionParamsCreator.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.auth + +import android.net.Uri +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.api.extensions.tryOrNull +import timber.log.Timber +import javax.inject.Inject + +internal interface SessionParamsCreator { + + suspend fun create( + credentials: Credentials, + homeServerConnectionConfig: HomeServerConnectionConfig, + loginType: LoginType, + ): SessionParams +} + +internal class DefaultSessionParamsCreator @Inject constructor( + private val isValidClientServerApiTask: IsValidClientServerApiTask +) : SessionParamsCreator { + + override suspend fun create( + credentials: Credentials, + homeServerConnectionConfig: HomeServerConnectionConfig, + loginType: LoginType, + ) = SessionParams( + credentials = credentials, + homeServerConnectionConfig = homeServerConnectionConfig.overrideWithCredentials(credentials), + isTokenValid = true, + loginType = loginType, + ) + + private suspend fun HomeServerConnectionConfig.overrideWithCredentials(credentials: Credentials) = copy( + homeServerUriBase = credentials.getHomeServerUri(this) ?: homeServerUriBase, + identityServerUri = credentials.getIdentityServerUri() ?: identityServerUri + ) + + private suspend fun Credentials.getHomeServerUri(homeServerConnectionConfig: HomeServerConnectionConfig) = + discoveryInformation?.homeServer?.baseURL + ?.trim { it == '/' } + ?.takeIf { it.isNotBlank() } + // It can be the same value, so in this case, do not check again the validity + ?.takeIf { it != homeServerConnectionConfig.homeServerUriBase.toString() } + ?.also { Timber.d("Overriding homeserver url to $it (will check if valid)") } + ?.let { Uri.parse(it) } + ?.takeIf { validateUri(it, homeServerConnectionConfig) } + + private suspend fun validateUri(uri: Uri, homeServerConnectionConfig: HomeServerConnectionConfig) = + // Validate the URL, if the configuration is wrong server side, do not override + tryOrNull { + performClientServerApiValidation(uri, homeServerConnectionConfig) + } ?: true // In case of other error (no network, etc.), consider it is valid... + + private suspend fun performClientServerApiValidation(uri: Uri, homeServerConnectionConfig: HomeServerConnectionConfig) = + isValidClientServerApiTask.execute( + IsValidClientServerApiTask.Params(homeServerConnectionConfig.copy(homeServerUriBase = uri)) + ).also { Timber.d("Overriding homeserver url: $it") } + + private fun Credentials.getIdentityServerUri() = discoveryInformation?.identityServer?.baseURL + ?.trim { it == '/' } + ?.takeIf { it.isNotBlank() } + ?.also { Timber.d("Overriding identity server url to $it") } + ?.let { Uri.parse(it) } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt index 88c6d04ee6..0bc7831f5c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt @@ -22,6 +22,7 @@ import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo001 import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo002 import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo003 import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo004 +import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo005 import timber.log.Timber import javax.inject.Inject @@ -33,7 +34,7 @@ internal class AuthRealmMigration @Inject constructor() : RealmMigration { override fun equals(other: Any?) = other is AuthRealmMigration override fun hashCode() = 4000 - val schemaVersion = 4L + val schemaVersion = 5L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.d("Migrating Auth Realm from $oldVersion to $newVersion") @@ -42,5 +43,6 @@ internal class AuthRealmMigration @Inject constructor() : RealmMigration { if (oldVersion < 2) MigrateAuthTo002(realm).perform() if (oldVersion < 3) MigrateAuthTo003(realm).perform() if (oldVersion < 4) MigrateAuthTo004(realm).perform() + if (oldVersion < 5) MigrateAuthTo005(realm).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt index ba1ab8147b..f6c883cac0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsEntity.kt @@ -26,5 +26,6 @@ internal open class SessionParamsEntity( var homeServerConnectionConfigJson: String = "", // Set to false when the token is invalid and the user has been soft logged out // In case of hard logout, this object is deleted from DB - var isTokenValid: Boolean = true + var isTokenValid: Boolean = true, + var loginType: String = "", ) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt index 86929b1afe..23923bf267 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.auth.db import com.squareup.moshi.Moshi +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.data.SessionParams @@ -37,7 +38,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) { if (credentials == null || homeServerConnectionConfig == null) { return null } - return SessionParams(credentials, homeServerConnectionConfig, entity.isTokenValid) + return SessionParams(credentials, homeServerConnectionConfig, entity.isTokenValid, LoginType.fromName(entity.loginType)) } fun map(sessionParams: SessionParams?): SessionParamsEntity? { @@ -54,7 +55,8 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) { sessionParams.userId, credentialsJson, homeServerConnectionConfigJson, - sessionParams.isTokenValid + sessionParams.isTokenValid, + sessionParams.loginType.name, ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt new file mode 100644 index 0000000000..2cf1b62a4c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.auth.db.migration + +import io.realm.DynamicRealm +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields +import org.matrix.android.sdk.internal.util.database.RealmMigrator +import timber.log.Timber + +internal class MigrateAuthTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) { + + override fun doMigrate(realm: DynamicRealm) { + Timber.d("Update SessionParamsEntity to add LoginType") + + realm.schema.get("SessionParamsEntity") + ?.addField(SessionParamsEntityFields.LOGIN_TYPE, String::class.java) + ?.setRequired(SessionParamsEntityFields.LOGIN_TYPE, true) + ?.transform { it.set(SessionParamsEntityFields.LOGIN_TYPE, LoginType.UNKNOWN.name) } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt index 656a4f671b..468e998407 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.auth.login import android.util.Patterns +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.login.LoginProfileInfo import org.matrix.android.sdk.api.auth.login.LoginWizard import org.matrix.android.sdk.api.auth.registration.RegisterThreePid @@ -78,7 +79,7 @@ internal class DefaultLoginWizard( authAPI.login(loginParams) } - return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) + return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.PASSWORD) } /** @@ -92,7 +93,7 @@ internal class DefaultLoginWizard( authAPI.login(loginParams) } - return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) + return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.SSO) } override suspend fun loginCustom(data: JsonDict): Session { @@ -100,7 +101,7 @@ internal class DefaultLoginWizard( authAPI.login(data) } - return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) + return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, LoginType.CUSTOM) } override suspend fun resetPassword(email: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt index c9311867c8..af42105756 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.auth.login import dagger.Lazy import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session @@ -77,7 +78,7 @@ internal class DefaultDirectLoginTask @Inject constructor( } } - return sessionCreator.createSession(credentials, params.homeServerConnectionConfig) + return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.DIRECT) } private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt index d6ec0297b4..56425cbc74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.auth.registration import kotlinx.coroutines.delay +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.registration.RegisterThreePid @@ -36,9 +37,9 @@ import org.matrix.android.sdk.internal.auth.db.PendingSessionData * This class execute the registration request and is responsible to keep the session of interactive authentication. */ internal class DefaultRegistrationWizard( - authAPI: AuthAPI, - private val sessionCreator: SessionCreator, - private val pendingSessionStore: PendingSessionStore + authAPI: AuthAPI, + private val sessionCreator: SessionCreator, + private val pendingSessionStore: PendingSessionStore ) : RegistrationWizard { private var pendingSessionData: PendingSessionData = pendingSessionStore.getPendingSessionData() ?: error("Pending session data should exist here") @@ -64,7 +65,7 @@ internal class DefaultRegistrationWizard( override suspend fun getRegistrationFlow(): RegistrationResult { val params = RegistrationParams() - return performRegistrationRequest(params) + return performRegistrationRequest(params, LoginType.PASSWORD) } override suspend fun createAccount( @@ -73,43 +74,43 @@ internal class DefaultRegistrationWizard( initialDeviceDisplayName: String? ): RegistrationResult { val params = RegistrationParams( - username = userName, - password = password, - initialDeviceDisplayName = initialDeviceDisplayName + username = userName, + password = password, + initialDeviceDisplayName = initialDeviceDisplayName ) - return performRegistrationRequest(params) - .also { - pendingSessionData = pendingSessionData.copy(isRegistrationStarted = true) - .also { pendingSessionStore.savePendingSessionData(it) } - } + return performRegistrationRequest(params, LoginType.PASSWORD) + .also { + pendingSessionData = pendingSessionData.copy(isRegistrationStarted = true) + .also { pendingSessionStore.savePendingSessionData(it) } + } } override suspend fun performReCaptcha(response: String): RegistrationResult { val safeSession = pendingSessionData.currentSession - ?: throw IllegalStateException("developer error, call createAccount() method first") + ?: throw IllegalStateException("developer error, call createAccount() method first") val params = RegistrationParams(auth = AuthParams.createForCaptcha(safeSession, response)) - return performRegistrationRequest(params) + return performRegistrationRequest(params, LoginType.PASSWORD) } override suspend fun acceptTerms(): RegistrationResult { val safeSession = pendingSessionData.currentSession - ?: throw IllegalStateException("developer error, call createAccount() method first") + ?: throw IllegalStateException("developer error, call createAccount() method first") val params = RegistrationParams(auth = AuthParams(type = LoginFlowTypes.TERMS, session = safeSession)) - return performRegistrationRequest(params) + return performRegistrationRequest(params, LoginType.PASSWORD) } override suspend fun addThreePid(threePid: RegisterThreePid): RegistrationResult { pendingSessionData = pendingSessionData.copy(currentThreePidData = null) - .also { pendingSessionStore.savePendingSessionData(it) } + .also { pendingSessionStore.savePendingSessionData(it) } return sendThreePid(threePid) } override suspend fun sendAgainThreePid(): RegistrationResult { val safeCurrentThreePid = pendingSessionData.currentThreePidData?.threePid - ?: throw IllegalStateException("developer error, call createAccount() method first") + ?: throw IllegalStateException("developer error, call createAccount() method first") return sendThreePid(safeCurrentThreePid) } @@ -125,7 +126,7 @@ internal class DefaultRegistrationWizard( ) pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1) - .also { pendingSessionStore.savePendingSessionData(it) } + .also { pendingSessionStore.savePendingSessionData(it) } val params = RegistrationParams( auth = if (threePid is RegisterThreePid.Email) { @@ -148,17 +149,17 @@ internal class DefaultRegistrationWizard( ) // Store data pendingSessionData = pendingSessionData.copy(currentThreePidData = ThreePidData.from(threePid, response, params)) - .also { pendingSessionStore.savePendingSessionData(it) } + .also { pendingSessionStore.savePendingSessionData(it) } // and send the sid a first time - return performRegistrationRequest(params) + return performRegistrationRequest(params, LoginType.PASSWORD) } override suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult { val safeParam = pendingSessionData.currentThreePidData?.registrationParams - ?: throw IllegalStateException("developer error, no pending three pid") + ?: throw IllegalStateException("developer error, no pending three pid") - return performRegistrationRequest(safeParam, delayMillis) + return performRegistrationRequest(safeParam, LoginType.PASSWORD, delayMillis) } override suspend fun handleValidateThreePid(code: String): RegistrationResult { @@ -167,19 +168,19 @@ internal class DefaultRegistrationWizard( private suspend fun validateThreePid(code: String): RegistrationResult { val registrationParams = pendingSessionData.currentThreePidData?.registrationParams - ?: throw IllegalStateException("developer error, no pending three pid") + ?: throw IllegalStateException("developer error, no pending three pid") val safeCurrentData = pendingSessionData.currentThreePidData ?: throw IllegalStateException("developer error, call createAccount() method first") val url = safeCurrentData.addThreePidRegistrationResponse.submitUrl ?: throw IllegalStateException("Missing url to send the code") val validationBody = ValidationCodeBody( - clientSecret = pendingSessionData.clientSecret, - sid = safeCurrentData.addThreePidRegistrationResponse.sid, - code = code + clientSecret = pendingSessionData.clientSecret, + sid = safeCurrentData.addThreePidRegistrationResponse.sid, + code = code ) val validationResponse = validateCodeTask.execute(ValidateCodeTask.Params(url, validationBody)) if (validationResponse.isSuccess()) { // The entered code is correct // Same than validate email - return performRegistrationRequest(registrationParams, 3_000) + return performRegistrationRequest(registrationParams, LoginType.PASSWORD, 3_000) } else { // The code is not correct throw Failure.SuccessError @@ -188,10 +189,10 @@ internal class DefaultRegistrationWizard( override suspend fun dummy(): RegistrationResult { val safeSession = pendingSessionData.currentSession - ?: throw IllegalStateException("developer error, call createAccount() method first") + ?: throw IllegalStateException("developer error, call createAccount() method first") val params = RegistrationParams(auth = AuthParams(type = LoginFlowTypes.DUMMY, session = safeSession)) - return performRegistrationRequest(params) + return performRegistrationRequest(params, LoginType.PASSWORD) } override suspend fun registrationCustom( @@ -204,25 +205,28 @@ internal class DefaultRegistrationWizard( mutableParams["session"] = safeSession val params = RegistrationCustomParams(auth = mutableParams) - return performRegistrationOtherRequest(params) + return performRegistrationOtherRequest(LoginType.CUSTOM, params) } private suspend fun performRegistrationRequest( registrationParams: RegistrationParams, + loginType: LoginType, delayMillis: Long = 0 ): RegistrationResult { delay(delayMillis) - return register { registerTask.execute(RegisterTask.Params(registrationParams)) } + return register(loginType) { registerTask.execute(RegisterTask.Params(registrationParams)) } } private suspend fun performRegistrationOtherRequest( - registrationCustomParams: RegistrationCustomParams + loginType: LoginType, + registrationCustomParams: RegistrationCustomParams, ): RegistrationResult { - return register { registerCustomTask.execute(RegisterCustomTask.Params(registrationCustomParams)) } + return register(loginType) { registerCustomTask.execute(RegisterCustomTask.Params(registrationCustomParams)) } } private suspend fun register( - execute: suspend () -> Credentials + loginType: LoginType, + execute: suspend () -> Credentials, ): RegistrationResult { val credentials = try { execute.invoke() @@ -237,8 +241,7 @@ internal class DefaultRegistrationWizard( } } - val session = - sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) + val session = sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig, loginType) return RegistrationResult.Success(session) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt index 56d9cc2143..7d52d9b2bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt @@ -20,6 +20,7 @@ import android.content.Context import io.realm.Realm import io.realm.RealmConfiguration import kotlinx.coroutines.runBlocking +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.DiscoveryInformation import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig @@ -145,7 +146,8 @@ internal class DefaultLegacySessionImporter @Inject constructor( forceUsageTlsVersions = legacyConfig.forceUsageOfTlsVersions() ), // If token is not valid, this boolean will be updated later - isTokenValid = true + isTokenValid = true, + loginType = LoginType.UNKNOWN, ) Timber.d("Migration: save session") diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005Test.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005Test.kt new file mode 100644 index 0000000000..95b226411b --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/db/migration/MigrateAuthTo005Test.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.auth.db.migration + +import org.junit.Test +import org.matrix.android.sdk.test.fakes.internal.auth.db.migration.Fake005MigrationRealm + +class MigrateAuthTo005Test { + + private val fakeRealm = Fake005MigrationRealm() + private val migrator = MigrateAuthTo005(fakeRealm.instance) + + @Test + fun `when doMigrate, then LoginType field added`() { + migrator.doMigrate(fakeRealm.instance) + + fakeRealm.verifyLoginTypeAdded() + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/login/LoginTypeTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/login/LoginTypeTest.kt new file mode 100644 index 0000000000..495302acb2 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/login/LoginTypeTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.auth.login + +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldNotBeEqualTo +import org.junit.Test +import org.matrix.android.sdk.api.auth.LoginType + +class LoginTypeTest { + + @Test + fun `when getting type fromName, then map correctly`() { + LoginType.fromName(LoginType.PASSWORD.name) shouldBeEqualTo LoginType.PASSWORD + LoginType.fromName(LoginType.SSO.name) shouldBeEqualTo LoginType.SSO + LoginType.fromName(LoginType.UNSUPPORTED.name) shouldBeEqualTo LoginType.UNSUPPORTED + LoginType.fromName(LoginType.CUSTOM.name) shouldBeEqualTo LoginType.CUSTOM + LoginType.fromName(LoginType.DIRECT.name) shouldBeEqualTo LoginType.DIRECT + LoginType.fromName(LoginType.UNKNOWN.name) shouldBeEqualTo LoginType.UNKNOWN + } + + @Test // The failure of this test means that an existing type has not been correctly added to fromValue + fun `given non-unknown type name, when getting type fromName, then type is not UNKNOWN`() { + val types = LoginType.values() + + types.forEach { type -> + if (type != LoginType.UNKNOWN) { + LoginType.fromName(type.name) shouldNotBeEqualTo LoginType.UNKNOWN + } + } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/api/FakeSession.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/api/FakeSession.kt new file mode 100644 index 0000000000..df22455fb1 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/api/FakeSession.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.api + +import io.mockk.mockk +import org.matrix.android.sdk.api.session.Session + +class FakeSession { + + val instance: Session = mockk() +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/FakeSessionManager.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/FakeSessionManager.kt new file mode 100644 index 0000000000..2232ad9b4f --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/FakeSessionManager.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.amshove.kluent.shouldBeEqualTo +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.SessionManager +import org.matrix.android.sdk.test.fakes.api.FakeSession + +internal class FakeSessionManager { + + val instance: SessionManager = mockk() + + init { + every { instance.getOrCreateSession(any()) } returns fakeSession.instance + } + + fun assertSessionCreatedWithParams(session: Session, sessionParams: SessionParams) { + verify { instance.getOrCreateSession(sessionParams) } + + session shouldBeEqualTo fakeSession.instance + } + + companion object { + private val fakeSession = FakeSession() + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeIsValidClientServerApiTask.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeIsValidClientServerApiTask.kt new file mode 100644 index 0000000000..40681748c1 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeIsValidClientServerApiTask.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth + +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.internal.auth.IsValidClientServerApiTask +import org.matrix.android.sdk.internal.auth.IsValidClientServerApiTask.Params + +internal class FakeIsValidClientServerApiTask { + + init { + coEvery { instance.execute(any()) } returns true + } + + val instance: IsValidClientServerApiTask = mockk() + + fun givenValidationFails() { + coEvery { instance.execute(any()) } returns false + } + + fun verifyExecutionWithConfig(config: HomeServerConnectionConfig) { + coVerify { instance.execute(Params(config)) } + } + + fun verifyNoExecution() { + coVerify(inverse = true) { instance.execute(any()) } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakePendingSessionStore.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakePendingSessionStore.kt new file mode 100644 index 0000000000..8a18b75ca2 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakePendingSessionStore.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth + +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.mockk +import org.matrix.android.sdk.internal.auth.PendingSessionStore + +internal class FakePendingSessionStore { + + val instance: PendingSessionStore = mockk() + + init { + coJustRun { instance.delete() } + } + + fun verifyPendingSessionDataCleared() { + coVerify { instance.delete() } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsCreator.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsCreator.kt new file mode 100644 index 0000000000..f64e5a451d --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsCreator.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.test.fakes.internal.auth + +import android.net.Uri +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.internal.auth.SessionParamsCreator +import org.matrix.android.sdk.test.fixtures.SessionParamsFixture.aSessionParams + +internal class FakeSessionParamsCreator { + + val instance: SessionParamsCreator = mockk() + + init { + mockkStatic(Uri::class) + every { Uri.parse(any()) } returns mockk() + coEvery { instance.create(any(), any(), any()) } returns sessionParams + } + + fun verifyCreatedWithParameters( + credentials: Credentials, + homeServerConnectionConfig: HomeServerConnectionConfig, + loginType: LoginType, + ) { + coVerify { instance.create(credentials, homeServerConnectionConfig, loginType) } + } + + companion object { + val sessionParams = aSessionParams() + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsStore.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsStore.kt new file mode 100644 index 0000000000..22e8a32a32 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/FakeSessionParamsStore.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth + +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.mockk +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.internal.auth.SessionParamsStore + +internal class FakeSessionParamsStore { + + val instance: SessionParamsStore = mockk() + + init { + coJustRun { instance.save(any()) } + } + + fun verifyParamsSaved(sessionParams: SessionParams) { + coVerify { instance.save(sessionParams) } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/migration/Fake005MigrationRealm.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/migration/Fake005MigrationRealm.kt new file mode 100644 index 0000000000..13fd4a972c --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/migration/Fake005MigrationRealm.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth.db.migration + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verifyOrder +import io.realm.DynamicRealm +import io.realm.RealmObjectSchema +import io.realm.RealmSchema +import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields + +class Fake005MigrationRealm { + + val instance: DynamicRealm = mockk() + + private val schema: RealmSchema = mockk() + private val objectSchema: RealmObjectSchema = mockk() + + init { + every { instance.schema } returns schema + every { schema.get("SessionParamsEntity") } returns objectSchema + every { objectSchema.addField(any(), any()) } returns objectSchema + every { objectSchema.setRequired(any(), any()) } returns objectSchema + every { objectSchema.transform(any()) } returns objectSchema + } + + fun verifyLoginTypeAdded() { + verifyLoginTypeFieldAddedAndTransformed() + } + + private fun verifyLoginTypeFieldAddedAndTransformed() { + verifyOrder { + objectSchema["SessionParamsEntity"] + objectSchema.addField(SessionParamsEntityFields.LOGIN_TYPE, String::class.java) + objectSchema.setRequired(SessionParamsEntityFields.LOGIN_TYPE, true) + objectSchema.transform(any()) + } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeCredentialsJsonAdapter.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeCredentialsJsonAdapter.kt new file mode 100644 index 0000000000..f1cb4071fd --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeCredentialsJsonAdapter.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams + +import com.squareup.moshi.JsonAdapter +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeSessionParamsMapperMoshi.Companion.sessionParams +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeSessionParamsMapperMoshi.Companion.sessionParamsEntity +import org.matrix.android.sdk.test.fixtures.CredentialsFixture.aCredentials + +internal class FakeCredentialsJsonAdapter { + + val instance: JsonAdapter = mockk() + + init { + every { instance.fromJson(sessionParamsEntity.credentialsJson) } returns credentials + every { instance.toJson(sessionParams.credentials) } returns CREDENTIALS_JSON + } + + fun givenNullDeserialization() { + every { instance.fromJson(sessionParamsEntity.credentialsJson) } returns null + } + + fun givenNullSerialization() { + every { instance.toJson(credentials) } returns null + } + + companion object { + val credentials = aCredentials() + const val CREDENTIALS_JSON = "credentials_json" + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeHomeServerConnectionConfigJsonAdapter.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeHomeServerConnectionConfigJsonAdapter.kt new file mode 100644 index 0000000000..f85d6e2778 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeHomeServerConnectionConfigJsonAdapter.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams + +import com.squareup.moshi.JsonAdapter +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeSessionParamsMapperMoshi.Companion.sessionParams +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeSessionParamsMapperMoshi.Companion.sessionParamsEntity + +internal class FakeHomeServerConnectionConfigJsonAdapter { + + val instance: JsonAdapter = mockk() + + init { + every { instance.fromJson(sessionParamsEntity.homeServerConnectionConfigJson) } returns homeServerConnectionConfig + every { instance.toJson(sessionParams.homeServerConnectionConfig) } returns HOME_SERVER_CONNECTION_CONFIG_JSON + } + + fun givenNullDeserialization() { + every { instance.fromJson(sessionParamsEntity.credentialsJson) } returns null + } + + fun givenNullSerialization() { + every { instance.toJson(homeServerConnectionConfig) } returns null + } + + companion object { + val homeServerConnectionConfig = HomeServerConnectionConfig.Builder().withHomeServerUri("homeserver").build() + const val HOME_SERVER_CONNECTION_CONFIG_JSON = "home_server_connection_config_json" + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeSessionParamsMapperMoshi.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeSessionParamsMapperMoshi.kt new file mode 100644 index 0000000000..ed0ddb1179 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/auth/db/sessionparams/FakeSessionParamsMapperMoshi.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams + +import android.net.Uri +import com.squareup.moshi.Moshi +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldBeNull +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.api.auth.data.sessionId +import org.matrix.android.sdk.internal.auth.db.SessionParamsEntity +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeCredentialsJsonAdapter.Companion.CREDENTIALS_JSON +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeCredentialsJsonAdapter.Companion.credentials +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeHomeServerConnectionConfigJsonAdapter.Companion.HOME_SERVER_CONNECTION_CONFIG_JSON +import org.matrix.android.sdk.test.fakes.internal.auth.db.sessionparams.FakeHomeServerConnectionConfigJsonAdapter.Companion.homeServerConnectionConfig +import org.matrix.android.sdk.test.fixtures.SessionParamsEntityFixture.aSessionParamsEntity +import org.matrix.android.sdk.test.fixtures.SessionParamsFixture.aSessionParams + +internal class FakeSessionParamsMapperMoshi { + + val instance: Moshi = mockk() + private val credentialsJsonAdapter = FakeCredentialsJsonAdapter() + private val homeServerConnectionConfigAdapter = FakeHomeServerConnectionConfigJsonAdapter() + + init { + mockkStatic(Uri::class) + every { Uri.parse(any()) } returns mockk() + every { instance.adapter(Credentials::class.java) } returns credentialsJsonAdapter.instance + every { instance.adapter(HomeServerConnectionConfig::class.java) } returns homeServerConnectionConfigAdapter.instance + } + + fun assertSessionParamsWasMappedSuccessfully(sessionParams: SessionParams?) { + sessionParams shouldBeEqualTo SessionParams( + credentials, + homeServerConnectionConfig, + sessionParamsEntity.isTokenValid, + LoginType.fromName(sessionParamsEntity.loginType) + ) + } + + fun assertSessionParamsIsNull(sessionParams: SessionParams?) { + sessionParams.shouldBeNull() + } + + fun assertSessionParamsEntityWasMappedSuccessfully(sessionParamsEntity: SessionParamsEntity?) { + sessionParamsEntity shouldBeEqualTo SessionParamsEntity( + sessionParams.credentials.sessionId(), + sessionParams.userId, + CREDENTIALS_JSON, + HOME_SERVER_CONNECTION_CONFIG_JSON, + sessionParams.isTokenValid, + sessionParams.loginType.name, + ) + } + + fun assertSessionParamsEntityIsNull(sessionParamsEntity: SessionParamsEntity?) { + sessionParamsEntity.shouldBeNull() + } + + companion object { + val sessionParams = aSessionParams() + val sessionParamsEntity = aSessionParamsEntity() + val nullSessionParams: SessionParams? = null + val nullSessionParamsEntity: SessionParamsEntity? = null + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/CredentialsFixture.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/CredentialsFixture.kt new file mode 100644 index 0000000000..2e7b36ff63 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/CredentialsFixture.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fixtures + +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.DiscoveryInformation + +object CredentialsFixture { + fun aCredentials( + userId: String = "", + accessToken: String = "", + refreshToken: String? = null, + homeServer: String? = null, + deviceId: String? = null, + discoveryInformation: DiscoveryInformation? = null, + ) = Credentials( + userId, + accessToken, + refreshToken, + homeServer, + deviceId, + discoveryInformation, + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/DiscoveryInformationFixture.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/DiscoveryInformationFixture.kt new file mode 100644 index 0000000000..c929a27d23 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/DiscoveryInformationFixture.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fixtures + +import org.matrix.android.sdk.api.auth.data.DiscoveryInformation +import org.matrix.android.sdk.api.auth.data.WellKnownBaseConfig + +object DiscoveryInformationFixture { + fun aDiscoveryInformation( + homeServer: WellKnownBaseConfig? = null, + identityServer: WellKnownBaseConfig? = null, + ) = DiscoveryInformation( + homeServer, + identityServer + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsEntityFixture.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsEntityFixture.kt new file mode 100644 index 0000000000..bbea232a22 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsEntityFixture.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fixtures + +import org.matrix.android.sdk.internal.auth.db.SessionParamsEntity + +internal object SessionParamsEntityFixture { + fun aSessionParamsEntity( + sessionId: String = "", + userId: String = "", + credentialsJson: String = "", + homeServerConnectionConfigJson: String = "", + isTokenValid: Boolean = true, + loginType: String = "", + ) = SessionParamsEntity( + sessionId, + userId, + credentialsJson, + homeServerConnectionConfigJson, + isTokenValid, + loginType, + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsFixture.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsFixture.kt new file mode 100644 index 0000000000..5cbbe1a47a --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/SessionParamsFixture.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fixtures + +import org.matrix.android.sdk.api.auth.LoginType +import org.matrix.android.sdk.api.auth.data.Credentials +import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig +import org.matrix.android.sdk.api.auth.data.SessionParams +import org.matrix.android.sdk.test.fixtures.CredentialsFixture.aCredentials + +object SessionParamsFixture { + fun aSessionParams( + credentials: Credentials = aCredentials(), + homeServerConnectionConfig: HomeServerConnectionConfig = HomeServerConnectionConfig.Builder().withHomeServerUri("homeserver").build(), + isTokenValid: Boolean = false, + loginType: LoginType = LoginType.UNKNOWN, + ) = SessionParams( + credentials, + homeServerConnectionConfig, + isTokenValid, + loginType, + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/WellKnownBaseConfigFixture.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/WellKnownBaseConfigFixture.kt new file mode 100644 index 0000000000..a33308dbd6 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fixtures/WellKnownBaseConfigFixture.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fixtures + +import org.matrix.android.sdk.api.auth.data.WellKnownBaseConfig + +object WellKnownBaseConfigFixture { + fun aWellKnownBaseConfig( + baseUrl: String? = null, + ) = WellKnownBaseConfig( + baseUrl, + ) +} diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index 722133f585..4cbebd67a3 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -37,6 +37,7 @@ import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.validateBackPressed import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.utils.openUrlInChromeCustomTab import im.vector.app.databinding.ActivityLoginBinding import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.home.HomeActivity @@ -231,9 +232,9 @@ open class LoginActivity : VectorBaseActivity(), UnlockedA } private fun inferAuthDescription(loginViewState: LoginViewState) = when (loginViewState.signMode) { - SignMode.Unknown -> null - SignMode.SignUp -> AuthenticationDescription.Register(type = AuthenticationDescription.AuthenticationType.Other) - SignMode.SignIn -> AuthenticationDescription.Login + SignMode.Unknown -> null + SignMode.SignUp -> AuthenticationDescription.Register(type = AuthenticationDescription.AuthenticationType.Other) + SignMode.SignIn -> AuthenticationDescription.Login SignMode.SignInWithMatrixId -> AuthenticationDescription.Login } @@ -272,8 +273,8 @@ open class LoginActivity : VectorBaseActivity(), UnlockedA SignMode.SignIn -> { // It depends on the LoginMode when (state.loginMode) { - LoginMode.Unknown, - is LoginMode.Sso -> error("Developer error") + LoginMode.Unknown -> error("Developer error") + is LoginMode.Sso -> launchSsoFlow() is LoginMode.SsoAndPassword, LoginMode.Password -> addFragmentToBackstack( views.loginFragmentContainer, @@ -293,6 +294,16 @@ open class LoginActivity : VectorBaseActivity(), UnlockedA } } + private fun launchSsoFlow() = withState(loginViewModel) { state -> + loginViewModel.getSsoUrl( + redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL, + deviceId = state.deviceId, + providerId = null, + )?.let { ssoUrl -> + openUrlInChromeCustomTab(this, null, ssoUrl) + } + } + /** * Handle the SSO redirection here. */ diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt index 1214ac6819..265cf3199e 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt @@ -18,6 +18,7 @@ package im.vector.app.features.signout.soft import com.airbnb.epoxy.EpoxyController import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized @@ -35,6 +36,7 @@ import im.vector.app.features.signout.soft.epoxy.loginRedButtonItem import im.vector.app.features.signout.soft.epoxy.loginTextItem import im.vector.app.features.signout.soft.epoxy.loginTitleItem import im.vector.app.features.signout.soft.epoxy.loginTitleSmallItem +import org.matrix.android.sdk.api.auth.LoginType import javax.inject.Inject class SoftLogoutController @Inject constructor( @@ -91,55 +93,76 @@ class SoftLogoutController @Inject constructor( } } - private fun buildForm(state: SoftLogoutViewState) { + private fun buildForm(state: SoftLogoutViewState) = when (state.asyncHomeServerLoginFlowRequest) { + is Fail -> buildLoginErrorWithRetryItem(state.asyncHomeServerLoginFlowRequest.error) + is Success -> buildLoginSuccessItem(state) + is Loading, Uninitialized -> buildLoadingItem() + is Incomplete -> Unit + } + + private fun buildLoadingItem() { + loadingItem { + id("loading") + } + } + + private fun buildLoginErrorWithRetryItem(error: Throwable) { val host = this - when (state.asyncHomeServerLoginFlowRequest) { - Uninitialized, - is Loading -> { - loadingItem { - id("loading") - } - } - is Fail -> { - loginErrorWithRetryItem { - id("errorRetry") - text(host.errorFormatter.toHumanReadable(state.asyncHomeServerLoginFlowRequest.error)) - listener { host.listener?.retry() } - } - } - is Success -> { - when (state.asyncHomeServerLoginFlowRequest.invoke()) { - LoginMode.Password -> { - loginPasswordFormItem { - id("passwordForm") - stringProvider(host.stringProvider) - passwordValue(state.enteredPassword) - submitEnabled(state.enteredPassword.isNotEmpty()) - onPasswordEdited { host.listener?.passwordEdited(it) } - errorText((state.asyncLoginAction as? Fail)?.error?.let { host.errorFormatter.toHumanReadable(it) }) - forgetPasswordClickListener { host.listener?.forgetPasswordClicked() } - submitClickListener { host.listener?.submit() } - } - } - is LoginMode.Sso -> { - loginCenterButtonItem { - id("sso") - text(host.stringProvider.getString(R.string.login_signin_sso)) - listener { host.listener?.signinFallbackSubmit() } - } - } - is LoginMode.SsoAndPassword -> { - } - LoginMode.Unsupported -> { - loginCenterButtonItem { - id("fallback") - text(host.stringProvider.getString(R.string.login_signin)) - listener { host.listener?.signinFallbackSubmit() } - } - } - LoginMode.Unknown -> Unit // Should not happen - } - } + loginErrorWithRetryItem { + id("errorRetry") + text(host.errorFormatter.toHumanReadable(error)) + listener { host.listener?.retry() } + } + } + + private fun buildLoginSuccessItem(state: SoftLogoutViewState) = when (state.asyncHomeServerLoginFlowRequest.invoke()) { + LoginMode.Password -> buildLoginPasswordForm(state) + is LoginMode.Sso -> buildLoginSSOForm() + is LoginMode.SsoAndPassword -> disambiguateLoginSSOAndPasswordForm(state) + LoginMode.Unsupported -> buildLoginUnsupportedForm() + LoginMode.Unknown, null -> Unit // Should not happen + } + + private fun buildLoginPasswordForm(state: SoftLogoutViewState) { + val host = this + loginPasswordFormItem { + id("passwordForm") + stringProvider(host.stringProvider) + passwordValue(state.enteredPassword) + submitEnabled(state.enteredPassword.isNotEmpty()) + onPasswordEdited { host.listener?.passwordEdited(it) } + errorText((state.asyncLoginAction as? Fail)?.error?.let { host.errorFormatter.toHumanReadable(it) }) + forgetPasswordClickListener { host.listener?.forgetPasswordClicked() } + submitClickListener { host.listener?.submit() } + } + } + + private fun buildLoginSSOForm() { + val host = this + loginCenterButtonItem { + id("sso") + text(host.stringProvider.getString(R.string.login_signin_sso)) + listener { host.listener?.signinFallbackSubmit() } + } + } + + private fun disambiguateLoginSSOAndPasswordForm(state: SoftLogoutViewState) { + when (state.loginType) { + LoginType.PASSWORD -> buildLoginPasswordForm(state) + LoginType.SSO -> buildLoginSSOForm() + LoginType.DIRECT, + LoginType.CUSTOM, + LoginType.UNSUPPORTED -> buildLoginUnsupportedForm() + LoginType.UNKNOWN -> Unit + } + } + + private fun buildLoginUnsupportedForm() { + val host = this + loginCenterButtonItem { + id("fallback") + text(host.stringProvider.getString(R.string.login_signin)) + listener { host.listener?.signinFallbackSubmit() } } } diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt index 34d001caad..9d0580638b 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt @@ -35,14 +35,12 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.login.LoginMode import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.AuthenticationService +import org.matrix.android.sdk.api.auth.LoginType import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getUser import timber.log.Timber -/** - * TODO Test push: disable the pushers? - */ class SoftLogoutViewModel @AssistedInject constructor( @Assisted initialState: SoftLogoutViewState, private val session: Session, @@ -70,7 +68,8 @@ class SoftLogoutViewModel @AssistedInject constructor( userId = userId, deviceId = session.sessionParams.deviceId.orEmpty(), userDisplayName = session.getUser(userId)?.displayName ?: userId, - hasUnsavedKeys = session.hasUnsavedKeys() + hasUnsavedKeys = session.hasUnsavedKeys(), + loginType = session.sessionParams.loginType, ) } else { SoftLogoutViewState( @@ -78,7 +77,8 @@ class SoftLogoutViewModel @AssistedInject constructor( userId = "", deviceId = "", userDisplayName = "", - hasUnsavedKeys = false + hasUnsavedKeys = false, + loginType = LoginType.UNKNOWN, ) } } diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt index 511711ab2f..28c8273412 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt @@ -22,6 +22,7 @@ import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import im.vector.app.features.login.LoginMode +import org.matrix.android.sdk.api.auth.LoginType data class SoftLogoutViewState( val asyncHomeServerLoginFlowRequest: Async = Uninitialized, @@ -31,7 +32,8 @@ data class SoftLogoutViewState( val deviceId: String, val userDisplayName: String, val hasUnsavedKeys: Boolean, - val enteredPassword: String = "" + val loginType: LoginType, + val enteredPassword: String = "", ) : MavericksState { fun isLoading(): Boolean { diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index cf94493f61..3af15a7e5c 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright (c) 2022 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.