Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ local.properties
/.kotlin/sessions/
/.kotlin/metadata/
/source/telemetry/build/
/samples/prebuilt-ui/build/
/samples/prebuilt-ui/build/
/docs/
2 changes: 2 additions & 0 deletions config/detekt/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
<ID>LongMethod:ClerkTextFieldSnapshotTest.kt$ClerkTextFieldSnapshotTest$@Test fun testClerkTextFieldError()</ID>
<ID>LongMethod:ClerkTextFieldSnapshotTest.kt$ClerkTextFieldSnapshotTest$@Test fun testClerkTextFieldUnfocused()</ID>
<ID>LongMethod:ConfigurationManager.kt$ConfigurationManager$private fun refreshClientAndEnvironment(options: ClerkConfigurationOptions?, retryCount: Int)</ID>
<ID>LongMethod:ConfigurationManager.kt$ConfigurationManager$private fun refreshClientAndEnvironment(options: ClerkConfigurationOptions?, retryCount: Int)</ID>
<ID>LongMethod:SignInFactorCodeView.kt$@Composable private fun SignInFactorCodeViewImpl( factor: Factor, modifier: Modifier = Modifier, viewModel: SignInFactorCodeViewModel = viewModel(), isSecondFactor: Boolean = false, isClientTrust: Boolean = false, onAuthComplete: () -> Unit, )</ID>
<ID>LongMethod:SignUpCollectFieldView.kt$@Composable private fun SignUpCollectFieldViewImpl( collectField: CollectField, collectFieldHelper: CollectFieldHelper, onAuthComplete: () -> Unit, modifier: Modifier = Modifier, viewModel: CollectFieldViewModel = viewModel(), )</ID>
<ID>LongMethod:SignUpCompleteProfileView.kt$@Composable private fun InputRow( firstEnabled: Boolean, lastEnabled: Boolean, first: String, last: String, onFirstChange: (String) -> Unit, onLastChange: (String) -> Unit, onFocusChange: (CompleteProfileField) -> Unit = {}, )</ID>
<ID>LongMethod:SignUpCompleteProfileView.kt$@Composable private fun SignUpCompleteProfileImpl( onAuthComplete: () -> Unit, modifier: Modifier = Modifier, firstName: String = "", lastName: String = "", firstNameEnabled: Boolean = false, lastNameEnabled: Boolean = false, legalConsentMissing: Boolean = false, viewModel: CompleteProfileViewModel = viewModel(), )</ID>
Expand Down
3 changes: 3 additions & 0 deletions source/api/src/main/kotlin/com/clerk/api/signin/SignIn.kt
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ data class SignIn(
/** The user needs to create a new password. */
@SerialName("needs_new_password") NEEDS_NEW_PASSWORD,

/** Client trust verification is required. */
@SerialName("needs_client_trust") NEEDS_CLIENT_TRUST,
Comment on lines +191 to +192
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add tests for the new NEEDS_CLIENT_TRUST status.

The enum addition looks correct, but no tests were included in this review. Please add tests to verify:

  • Serialization/deserialization of the new status value
  • Handling of this status in the sign-in flow
🤖 Prompt for AI Agents
In source/api/src/main/kotlin/com/clerk/api/signin/SignIn.kt around lines 191 to
192, the new enum value NEEDS_CLIENT_TRUST was added but there are no tests
covering it; add unit tests that (1) verify JSON serialization and
deserialization of the NEEDS_CLIENT_TRUST enum value (round-trip encode->decode
produces the same enum and the serialized string equals "needs_client_trust"),
and (2) exercise the sign-in flow behavior when a response/state returns
NEEDS_CLIENT_TRUST (mock the sign-in service or controller to return this status
and assert the downstream handling, e.g. that the controller maps it to the
expected HTTP response/redirect or that the state machine transitions
appropriately). Place serialization tests alongside existing SignIn
enum/serialization tests (e.g. in test/kotlin/com/clerk/api/signin/) and place
sign-in flow tests with the sign-in controller/service tests, using existing
test fixtures/mocks and assertions to mirror other status tests.


/** The sign-in process is in an unknown state. */
UNKNOWN,
}
Expand Down
5 changes: 5 additions & 0 deletions source/ui/src/main/java/com/clerk/ui/auth/AuthState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ internal class AuthState(
} ?: backStack.add(AuthDestination.SignInGetHelp)
}
SignIn.Status.NEEDS_NEW_PASSWORD -> backStack.add(AuthDestination.SignInSetNewPassword)
SignIn.Status.NEEDS_CLIENT_TRUST -> {
signIn.startingSecondFactor?.let {
backStack.add(AuthDestination.SignInClientTrust(factor = it))
} ?: backStack.add(AuthDestination.SignInGetHelp)
}
SignIn.Status.UNKNOWN -> return
}
}
Expand Down
6 changes: 6 additions & 0 deletions source/ui/src/main/java/com/clerk/ui/auth/AuthView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.clerk.ui.core.composition.LocalTelemetryCollector
import com.clerk.ui.signin.SignInFactorOneView
import com.clerk.ui.signin.SignInFactorTwoView
import com.clerk.ui.signin.alternativemethods.SignInFactorAlternativeMethodsView
import com.clerk.ui.signin.clienttrust.SignInClientTrustView
import com.clerk.ui.signin.help.SignInGetHelpView
import com.clerk.ui.signin.password.forgot.SignInFactorOneForgotPasswordView
import com.clerk.ui.signin.password.reset.SignInSetNewPasswordView
Expand Down Expand Up @@ -97,6 +98,9 @@ fun AuthView(modifier: Modifier = Modifier, clerkTheme: ClerkTheme? = null) {
SignInSetNewPasswordView(onAuthComplete = { backStack.clear() })
}
entry<AuthDestination.SignInGetHelp> { SignInGetHelpView() }
entry<AuthDestination.SignInClientTrust> { key ->
SignInClientTrustView(factor = key.factor, onAuthComplete = { backStack.clear() })
}
entry<AuthDestination.SignUpCollectField> { key ->
SignUpCollectFieldView(field = key.field, onAuthComplete = { backStack.clear() })
}
Expand Down Expand Up @@ -149,6 +153,8 @@ internal object AuthDestination {

@Serializable data object SignInGetHelp : NavKey

@Serializable data class SignInClientTrust(val factor: Factor) : NavKey

@Serializable data class SignUpCollectField(val field: CollectField) : NavKey

@Serializable data class SignUpCode(val field: SignUpCodeField) : NavKey
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.clerk.ui.signin.clienttrust

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.clerk.api.network.model.factor.Factor
import com.clerk.api.ui.ClerkTheme
import com.clerk.ui.R
import com.clerk.ui.auth.PreviewAuthStateProvider
import com.clerk.ui.core.common.StrategyKeys
import com.clerk.ui.core.dimens.dp16
import com.clerk.ui.signin.code.SignInFactorCodeView
import com.clerk.ui.signin.help.SignInGetHelpView
import com.clerk.ui.theme.ClerkMaterialTheme
import com.clerk.ui.theme.ClerkThemeOverrideProvider

/**
* A composable that displays the client trust verification view.
*
* This view is shown when the user is signing in from a new or untrusted device and needs to
* complete an additional verification step. It displays a warning message explaining why
* verification is needed, followed by the code input for verification.
*
* Based on the `strategy` of the provided [factor], this composable will delegate rendering to
* [SignInFactorCodeView] for phone code or email code verification, or [SignInGetHelpView] for
* unsupported strategies.
*
* @param factor The factor to be verified for client trust.
* @param modifier The [Modifier] to be applied to the view.
* @param clerkTheme Optional theme override for customization.
* @param onAuthComplete Callback invoked when authentication is complete.
*/
@Composable
fun SignInClientTrustView(
factor: Factor,
modifier: Modifier = Modifier,
clerkTheme: ClerkTheme? = null,
onAuthComplete: () -> Unit,
) {
ClerkThemeOverrideProvider(clerkTheme) {
when (factor.strategy) {
StrategyKeys.PHONE_CODE,
StrategyKeys.EMAIL_CODE ->
SignInFactorCodeView(
factor = factor,
isSecondFactor = true,
isClientTrust = true,
modifier = modifier,
onAuthComplete = onAuthComplete,
)
else -> SignInGetHelpView(modifier = modifier)
}
}
}

/**
* A composable that displays a warning message for client trust verification.
*
* This message informs the user that they are signing in from a new device and explains why
* additional verification is being requested.
*/
@Composable
internal fun ClientTrustWarningMessage(modifier: Modifier = Modifier) {
Text(
text = stringResource(R.string.signing_in_from_new_device),
color = ClerkMaterialTheme.colors.warning,
style = ClerkMaterialTheme.typography.bodySmall,
textAlign = TextAlign.Center,
modifier = modifier.padding(bottom = dp16),
)
}

@PreviewLightDark
@Composable
private fun Preview() {
PreviewAuthStateProvider {
SignInClientTrustView(
factor = Factor(StrategyKeys.EMAIL_CODE, safeIdentifier = "[email protected]"),
onAuthComplete = {},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.clerk.ui.core.composition.LocalAuthState
import com.clerk.ui.core.input.ClerkCodeInputField
import com.clerk.ui.core.scaffold.ClerkThemedAuthScaffold
import com.clerk.ui.core.spacers.Spacers
import com.clerk.ui.signin.clienttrust.ClientTrustWarningMessage
import com.clerk.ui.theme.ClerkMaterialTheme
import com.clerk.ui.theme.ClerkThemeOverrideProvider

Expand Down Expand Up @@ -54,6 +55,7 @@ fun SignInFactorCodeView(
factor: Factor,
modifier: Modifier = Modifier,
isSecondFactor: Boolean = false,
isClientTrust: Boolean = false,
clerkTheme: ClerkTheme? = null,
onAuthComplete: () -> Unit,
) {
Expand All @@ -62,6 +64,7 @@ fun SignInFactorCodeView(
factor = factor,
modifier = modifier,
isSecondFactor = isSecondFactor,
isClientTrust = isClientTrust,
onAuthComplete = onAuthComplete,
)
}
Expand All @@ -87,6 +90,7 @@ private fun SignInFactorCodeViewImpl(
modifier: Modifier = Modifier,
viewModel: SignInFactorCodeViewModel = viewModel(),
isSecondFactor: Boolean = false,
isClientTrust: Boolean = false,
onAuthComplete: () -> Unit,
) {
val authState = LocalAuthState.current
Expand Down Expand Up @@ -116,6 +120,9 @@ private fun SignInFactorCodeViewImpl(
snackbarHostState = snackbarHostState,
onClickIdentifier = { authState.clearBackStack() },
) {
if (isClientTrust) {
ClientTrustWarningMessage()
}
ClerkCodeInputField(
verificationState = verificationTextState.verificationState(),
onTextChange = {
Expand Down Expand Up @@ -180,7 +187,7 @@ private fun PreviewSignInFactorCodeView() {
* - [Success]: Code verification succeeded
* - [Error]: Code verification failed
*/
internal sealed interface VerificationState {
sealed interface VerificationState {

/**
* Default state indicating the component is ready for user input. Typically shows normal input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private fun Preview() {
}

@Serializable
internal sealed interface SignUpCodeField {
sealed interface SignUpCodeField {
val value: String

@Serializable data class Phone(override val value: String) : SignUpCodeField
Expand Down
1 change: 1 addition & 0 deletions source/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
<string name="last_name">Last name</string>
<string name="facing_issues_you_can_use_any_of_these_methods_to_sign_in">Facing issues? You can use any of these methods to sign in.</string>
<string name="two_step_verification">Two-step verification</string>
<string name="signing_in_from_new_device">You\'re signing in from a new device. We\'re asking for verification to keep your account secure.</string>
<string name="when_signing_in_you_will_need_to_enter_a_verification_code">When signing in, you will need to enter a verification code sent to this phone number as an additional step.\n\nSave these backup codes and store them somewhere safe. If you lose access to your authentication device, you can use backup codes to sign in.</string>
<string name="two_step_verification_is_now_enabled">Two-step verification is now enabled. When signing in, you will need to enter a verification code from this authenticator app as an additional step.\n\nSave these backup codes and store them somewhere safe. If you lose access to your authentication device, you can use backup codes to sign in.</string>
<string name="backup_codes_are_now_enabled">Backup codes are now enabled. You can use one of these to sign in to your account, if you lose access to your authentication device. Each code can only be used once.</string>
Expand Down