From bee7ab319171394ca9682cf26b59095c009548c2 Mon Sep 17 00:00:00 2001
From: Taras Smakula <tarassmakula@gmail.com>
Date: Fri, 23 Feb 2024 16:52:49 +0200
Subject: [PATCH] Prepare stages for forgot password

---
 .../auth/feature/log_in/LogInViewModel.kt     |  6 +--
 .../auth/feature/log_in/LoginDataSource.kt    | 47 +++++++++++++++----
 2 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInViewModel.kt
index 8fe718a67..006376514 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInViewModel.kt
@@ -24,7 +24,7 @@ class LogInViewModel @Inject constructor(
     fun startLogInFlow(userName: String, domain: String, isForgotPassword: Boolean) {
         switchUserDataSource.getSessionCredentialsIdByUserInfo(userName, domain)
             ?.let { resumeSwitchUserSession(it) }
-            ?: login(userName, domain)
+            ?: login(userName, domain, isForgotPassword)
     }
 
     fun removeSwitchUser(id: String) {
@@ -43,9 +43,9 @@ class LogInViewModel @Inject constructor(
         }
     }
 
-    private fun login(userName: String, domain: String) {
+    private fun login(userName: String, domain: String, isForgotPassword: Boolean) {
         launchBg {
-            val loginResult = loginDataSource.startLogin(userName, domain)
+            val loginResult = loginDataSource.startLogin(userName, domain, isForgotPassword)
             loginResultLiveData.postValue(loginResult)
         }
     }
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LoginDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LoginDataSource.kt
index decc0120d..b117d4fc2 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LoginDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LoginDataSource.kt
@@ -3,12 +3,14 @@ package org.futo.circles.auth.feature.log_in
 import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.auth.R
+import org.futo.circles.auth.base.BaseLoginStagesDataSource
 import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.DIRECT_LOGIN_PASSWORD_TYPE
 import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.LOGIN_PASSWORD_TYPE
 import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.LOGIN_PASSWORD_USER_ID_TYPE
 import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.TYPE_PARAM_KEY
 import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.USER_PARAM_KEY
 import org.futo.circles.auth.feature.log_in.stages.LoginStagesDataSource
+import org.futo.circles.auth.feature.sign_up.SignUpDataSource
 import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixInstanceProvider
 import org.futo.circles.core.utils.HomeServerUtils.buildHomeServerConfigFromDomain
@@ -24,35 +26,64 @@ class LoginDataSource @Inject constructor(
 
     suspend fun startLogin(
         userName: String,
-        domain: String
+        domain: String,
+        isForgotPassword: Boolean
     ) = createResult {
         authService.cancelPendingLoginOrRegistration()
-        val stages = prepareLoginStages(userName, domain)
+        val stages = prepareLoginStages(userName, domain, isForgotPassword)
         loginStagesDataSource.startLoginStages(stages, userName, domain)
     }
 
     private suspend fun prepareLoginStages(
         userName: String,
-        domain: String
+        domain: String,
+        isForgotPassword: Boolean
     ): List<Stage> {
         val homeServerConfig = buildHomeServerConfigFromDomain(domain)
         val supportedLoginMethods = authService.getLoginFlow(homeServerConfig).supportedLoginTypes
 
-        return if (isPasswordLogin(supportedLoginMethods))
-            listOf(Stage.Other(true, DIRECT_LOGIN_PASSWORD_TYPE, null))
-        else getCircleLoginStages(userName, domain)
+        return if (isPasswordLogin(supportedLoginMethods)) {
+            if (isForgotPassword) throw IllegalArgumentException("Forgot password is only available for Circles domains")
+            else listOf(Stage.Other(true, DIRECT_LOGIN_PASSWORD_TYPE, null))
+        } else getCircleStages(userName, domain, isForgotPassword)
     }
 
     private fun isPasswordLogin(methods: List<String>) = methods.contains(LOGIN_PASSWORD_TYPE)
 
-    private suspend fun getCircleLoginStages(userName: String, domain: String): List<Stage> {
+    private suspend fun getCircleStages(
+        userName: String,
+        domain: String,
+        isForgotPassword: Boolean
+    ): List<Stage> {
         val identifierParams = mapOf(
             USER_PARAM_KEY to "@$userName:$domain",
             TYPE_PARAM_KEY to LOGIN_PASSWORD_USER_ID_TYPE
         )
         val flows = authService.getLoginWizard()
             .getAllLoginFlows(identifierParams, context.getString(R.string.initial_device_name))
-        return flows.firstOrNull()
+
+        val stages = if (isForgotPassword) getCircleStagesForForgotPassword(flows)
+        else getCircleStagesForLogin(flows)
+
+        return stages
             ?: throw IllegalArgumentException(context.getString(R.string.unsupported_login_method))
     }
+
+    private fun getCircleStagesForLogin(flows: List<List<Stage>>): List<Stage>? =
+        flows.firstOrNull { stages ->
+            stages.firstOrNull { stage ->
+                (stage as? Stage.Other)?.type == BaseLoginStagesDataSource.LOGIN_BSSPEKE_VERIFY_TYPE
+            } != null
+        }
+
+    private fun getCircleStagesForForgotPassword(flows: List<List<Stage>>): List<Stage>? =
+        flows.firstOrNull { stages ->
+            val containsEmailStage = stages.firstOrNull { stage ->
+                (stage as? Stage.Other)?.type == SignUpDataSource.REGISTRATION_EMAIL_SUBMIT_TOKEN_TYPE
+            } != null
+            val containsSetPassword = stages.firstOrNull { stage ->
+                (stage as? Stage.Other)?.type == SignUpDataSource.REGISTRATION_BSSPEKE_SAVE_TYPE
+            } != null
+            containsEmailStage && containsSetPassword
+        }
 }
\ No newline at end of file
-- 
GitLab