feat: improvements at login
- password field is now recognised by the system keyboard - TOTP six-digit input is now a numbers-only field - document API functions related to login - basic logout in API - insecure MFA-less accounts can now log in (SAD!)
This commit is contained in:
parent
8b40f122d3
commit
dff518bde7
|
|
@ -54,7 +54,9 @@ val RevoltHttp = HttpClient(OkHttp) {
|
|||
object RevoltAPI {
|
||||
const val TOKEN_HEADER_NAME = "x-session-token"
|
||||
|
||||
val userCache = mutableMapOf<String, CompleteUser>()
|
||||
// discount caching solution(/-s)! LRU would be better but this is fine for now, until it's not...
|
||||
val userCache =
|
||||
mutableMapOf<String, CompleteUser>()
|
||||
|
||||
var selfId: String? = null
|
||||
|
||||
|
|
@ -71,9 +73,23 @@ object RevoltAPI {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user is logged in and the current user has been fetched at least once.
|
||||
* Call [initialize] to fetch the current user first, else this will return false.
|
||||
*/
|
||||
fun isLoggedIn(): Boolean {
|
||||
return selfId != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the API client's state completely.
|
||||
*/
|
||||
fun logout() {
|
||||
selfId = null
|
||||
sessionToken = ""
|
||||
|
||||
userCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package chat.revolt.components.generic
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
|
||||
|
|
@ -15,13 +17,14 @@ fun FormTextField(
|
|||
label: String,
|
||||
onChange: (it: String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
password: Boolean = false,
|
||||
type: KeyboardType = KeyboardType.Text,
|
||||
) {
|
||||
TextField(
|
||||
value = value,
|
||||
onValueChange = onChange,
|
||||
singleLine = true,
|
||||
visualTransformation = if (password) PasswordVisualTransformation() else VisualTransformation.None,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = type),
|
||||
visualTransformation = if (type == KeyboardType.Password) PasswordVisualTransformation() else VisualTransformation.None,
|
||||
label = { Text(label) },
|
||||
modifier = modifier
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
|
@ -22,6 +23,7 @@ import chat.revolt.R
|
|||
import chat.revolt.api.REVOLT_SUPPORT
|
||||
import chat.revolt.api.routes.account.EmailPasswordAssessment
|
||||
import chat.revolt.api.routes.account.negotiateAuthentication
|
||||
import chat.revolt.api.routes.user.fetchSelfWithNewToken
|
||||
import chat.revolt.components.generic.AnyLink
|
||||
import chat.revolt.components.generic.FormTextField
|
||||
import chat.revolt.components.generic.Weblink
|
||||
|
|
@ -40,9 +42,9 @@ class LoginViewModel() : ViewModel() {
|
|||
val error: String?
|
||||
get() = _error
|
||||
|
||||
private var _navigateToMfa by mutableStateOf(false)
|
||||
val navigateToMfa: Boolean
|
||||
get() = _navigateToMfa
|
||||
private var _navigateTo by mutableStateOf<String?>(null)
|
||||
val navigateTo: String?
|
||||
get() = _navigateTo
|
||||
|
||||
private var _mfaResponse by mutableStateOf<EmailPasswordAssessment?>(null)
|
||||
val mfaResponse: EmailPasswordAssessment?
|
||||
|
|
@ -60,19 +62,21 @@ class LoginViewModel() : ViewModel() {
|
|||
if (response.proceedMfa) {
|
||||
Log.d("Login", "MFA required. Navigating to MFA screen")
|
||||
_mfaResponse = response
|
||||
_navigateToMfa = true
|
||||
_navigateTo = "mfa"
|
||||
} else {
|
||||
Log.d(
|
||||
"Login",
|
||||
"No MFA required. Login is complete! We have a session token: ${response.firstUserHints!!.token}"
|
||||
)
|
||||
fetchSelfWithNewToken(response.firstUserHints.token)
|
||||
_navigateTo = "home"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun mfaComplete() {
|
||||
_navigateToMfa = false
|
||||
fun navigationComplete() {
|
||||
_navigateTo = null
|
||||
}
|
||||
|
||||
fun setEmail(email: String) {
|
||||
|
|
@ -89,7 +93,7 @@ fun LoginScreen(
|
|||
navController: NavController,
|
||||
viewModel: LoginViewModel = viewModel()
|
||||
) {
|
||||
if (viewModel.navigateToMfa) {
|
||||
if (viewModel.navigateTo == "mfa") {
|
||||
navController.navigate(
|
||||
"setup/mfa/${viewModel.mfaResponse!!.mfaSpec!!.ticket}/${
|
||||
viewModel.mfaResponse!!.mfaSpec!!.allowedMethods.joinToString(
|
||||
|
|
@ -97,7 +101,12 @@ fun LoginScreen(
|
|||
)
|
||||
}"
|
||||
)
|
||||
viewModel.mfaComplete()
|
||||
viewModel.navigationComplete()
|
||||
} else if (viewModel.navigateTo == "home") {
|
||||
navController.navigate("chat/home") {
|
||||
popUpTo("setup/greeting") { inclusive = true }
|
||||
}
|
||||
viewModel.navigationComplete()
|
||||
}
|
||||
|
||||
Column(
|
||||
|
|
@ -143,7 +152,7 @@ fun LoginScreen(
|
|||
FormTextField(
|
||||
value = viewModel.password,
|
||||
label = stringResource(R.string.password),
|
||||
password = true,
|
||||
type = KeyboardType.Password,
|
||||
onChange = { viewModel.setPassword(it) })
|
||||
|
||||
AnyLink(
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
|
@ -197,6 +198,7 @@ fun MfaScreen(
|
|||
FormTextField(
|
||||
label = stringResource(R.string.mfa_totp_code),
|
||||
onChange = { viewModel.setTotpCode(it) },
|
||||
type = KeyboardType.Number,
|
||||
value = viewModel.totpCode,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue