diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt index 932ffbead9..e7cb72544b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt @@ -21,12 +21,18 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.internal.auth.data.LoginFlowResponse /** * This interface defines methods to authenticate to a matrix server. */ interface Authenticator { + /** + * Request the supported login flows for this homeserver + */ + fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback): Cancelable + /** * @param homeServerConnectionConfig this param is used to configure the Homeserver * @param login the login field diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt index d795a3c413..d42962c53e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthAPI.kt @@ -17,10 +17,12 @@ package im.vector.matrix.android.internal.auth import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.internal.auth.data.LoginFlowResponse import im.vector.matrix.android.internal.auth.data.PasswordLoginParams import im.vector.matrix.android.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.Headers import retrofit2.http.POST @@ -29,6 +31,13 @@ import retrofit2.http.POST */ internal interface AuthAPI { + /** + * Get the supported login flow + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-login + */ + @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "login") + fun getLoginFlows(): Call + /** * Pass params to the server for the current login phase. * Set all the timeouts to 1 minute diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt index adea7c894b..765f410d3f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.SessionManager +import im.vector.matrix.android.internal.auth.data.LoginFlowResponse import im.vector.matrix.android.internal.auth.data.PasswordLoginParams import im.vector.matrix.android.internal.auth.data.ThreePidMedium import im.vector.matrix.android.internal.di.Unauthenticated @@ -62,11 +63,20 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated return sessionManager.getOrCreateSession(sessionParams) } + override fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback): Cancelable { + val job = GlobalScope.launch(coroutineDispatchers.main) { + val result = runCatching { + getLoginFlowInternal(homeServerConnectionConfig) + } + result.foldToCallback(callback) + } + return CancelableCoroutine(job) + } + override fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback): Cancelable { - val job = GlobalScope.launch(coroutineDispatchers.main) { val sessionOrFailure = runCatching { authenticate(homeServerConnectionConfig, login, password) @@ -74,7 +84,14 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated sessionOrFailure.foldToCallback(callback) } return CancelableCoroutine(job) + } + private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig) = withContext(coroutineDispatchers.io) { + val authAPI = buildAuthAPI(homeServerConnectionConfig) + + executeRequest { + apiCall = authAPI.getLoginFlows() + } } private suspend fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt index 834b0aee16..78fd372beb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/data/LoginFlowResponse.kt @@ -20,7 +20,7 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -internal data class LoginFlowResponse( +data class LoginFlowResponse( @Json(name = "flows") val flows: List ) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt index 4f3130c5ce..2061d03bed 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt @@ -35,7 +35,7 @@ internal object NetworkModule { @Provides @JvmStatic - fun providesHttpLogingInterceptor(): HttpLoggingInterceptor { + fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor { val logger = FormattedJsonHttpLogger() val interceptor = HttpLoggingInterceptor(logger) interceptor.level = BuildConfig.OKHTTP_LOGGING_LEVEL diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index d803b451ac..5bd7152cbb 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -128,6 +128,28 @@ class LoginFragment : VectorBaseFragment() { } override fun invalidate() = withState(viewModel) { state -> + when (state.asyncHomeServerLoginFlowRequest) { + is Loading -> { + progressBar.isVisible = true + touchArea.isVisible = true + + passwordShown = false + renderPasswordField() + } + is Fail -> { + progressBar.isVisible = false + touchArea.isVisible = false + Toast.makeText(requireActivity(), "Authenticate failure: ${state.asyncHomeServerLoginFlowRequest.error}", Toast.LENGTH_LONG).show() + } + is Success -> { + progressBar.isVisible = false + touchArea.isVisible = false + + // Check login flow + // TODO + } + } + when (state.asyncLoginAction) { is Loading -> { progressBar.isVisible = true diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index cf73f2517a..9eee9d2074 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.util.Cancelable +import im.vector.matrix.android.internal.auth.data.LoginFlowResponse import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.extensions.configureAndStart import im.vector.riotx.core.platform.VectorViewModel @@ -104,6 +105,8 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi } private fun handleUpdateHomeserver(action: LoginActions.UpdateHomeServer) { + currentTask?.cancel() + Try { val homeServerUri = action.homeServerUrl homeServerConnectionConfig = HomeServerConnectionConfig.Builder() @@ -111,22 +114,49 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi .build() } + val homeServerConnectionConfigFinal = homeServerConnectionConfig - // TODO Do request + if (homeServerConnectionConfigFinal == null) { + // This is invalid + setState { + copy( + asyncHomeServerLoginFlowRequest = Fail(Throwable("Baf format")) + ) + } + } else { - /* - currentTask?.cancel() + setState { + copy( + asyncHomeServerLoginFlowRequest = Loading() + ) + } + + + currentTask = authenticator.getLoginFlow(homeServerConnectionConfigFinal, object : MatrixCallback { + override fun onFailure(failure: Throwable) { + setState { + copy( + asyncHomeServerLoginFlowRequest = Fail(failure) + ) + } + } + + override fun onSuccess(data: LoginFlowResponse) { + setState { + copy( + asyncHomeServerLoginFlowRequest = Success(data) + ) + } + + handleLoginFlowResponse(data) + } + }) - setState { - copy( - asyncHomeServerLoginFlowRequest = Loading() - ) } + } + private fun handleLoginFlowResponse(loginFlowResponse: LoginFlowResponse) { - // TODO currentTask = - - */ } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt index f296e5e064..32c5c43bed 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewState.kt @@ -19,12 +19,9 @@ package im.vector.riotx.features.login import com.airbnb.mvrx.Async import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized +import im.vector.matrix.android.internal.auth.data.LoginFlowResponse data class LoginViewState( val asyncLoginAction: Async = Uninitialized, - val asyncHomeServerLoginFlowRequest: Async = Uninitialized + val asyncHomeServerLoginFlowRequest: Async = Uninitialized ) : MvRxState - - -// TODO Remove -data class LoginFlowResult(val remover: Boolean) \ No newline at end of file