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
4 changes: 3 additions & 1 deletion android/src/main/java/io/rownd/android/Rownd.kt
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,9 @@ abstract class RowndSignInOptionsBase() {
data class RowndSignInOptions(
@SerialName("post_login_redirect")
var postSignInRedirect: String? = Rownd.config.postSignInRedirect,
var intent: RowndSignInIntent? = null
var intent: RowndSignInIntent? = null,
var title: String? = null,
var subtitle: String? = null,
) : RowndSignInOptionsBase() {
override fun toJsonString(): String {
return json.encodeToString(serializer(), this)
Expand Down
6 changes: 6 additions & 0 deletions android/src/main/java/io/rownd/android/models/RowndConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ data class RowndConfig(
@Transient
var subdomainExtension: String = ".rownd.link",
@Transient
var forceInstantUserConversion: Boolean = false,
@Transient
var enableDebugMode: Boolean = false,

// Internals
@Transient
internal var stateFileName: String = "rownd_state.json"
) {
@Inject
Expand Down
3 changes: 2 additions & 1 deletion android/src/main/java/io/rownd/android/models/domain/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.util.Log
import io.rownd.android.models.repos.StateRepo
import io.rownd.android.models.repos.UserRepo
import io.rownd.android.util.AnyValueSerializer
import io.rownd.android.util.AuthLevel
import io.rownd.android.util.Encryption
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -15,7 +16,7 @@ data class User(
val redacted: MutableList<String> = mutableListOf(),
val state: String? = "enabled",
@SerialName("auth_level")
val authLevel: String? = "unverified",
val authLevel: AuthLevel? = AuthLevel.Unverified,
var isLoading: Boolean = false
) {
fun asNetworkModel(stateRepo: StateRepo, userRepo: UserRepo): NetworkUser {
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/java/io/rownd/android/models/network/Auth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ data class TokenRequestBody internal constructor(
val appId: String? = null,
@SerialName("intent")
val intent: RowndSignInIntent? = null,
@SerialName("instant_user_id")
var instantUserId: String? = null,
)

@Serializable
Expand Down
7 changes: 5 additions & 2 deletions android/src/main/java/io/rownd/android/models/network/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.rownd.android.models.domain.AppSchemaEncryptionState
import io.rownd.android.models.repos.StateRepo
import io.rownd.android.models.repos.UserRepo
import io.rownd.android.util.AnyValueSerializer
import io.rownd.android.util.AuthLevel
import io.rownd.android.util.Encryption
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -16,12 +17,14 @@ data class User(
val redacted: List<String> = listOf(),
val state: String? = "enabled",
@SerialName("auth_level")
val authLevel: String? = null
val authLevel: AuthLevel? = null
) {
fun asDomainModel(stateRepo: StateRepo, userRepo: UserRepo): DomainUser {
return DomainUser(
data = dataAsDecrypted(stateRepo, userRepo),
redacted = redacted.toMutableList()
redacted = redacted.toMutableList(),
state = state,
authLevel = authLevel
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.rownd.android.models.network.SignOutRequestBody
import io.rownd.android.models.network.SignOutResponse
import io.rownd.android.models.network.TokenRequestBody
import io.rownd.android.models.network.TokenResponse
import io.rownd.android.util.AuthLevel
import io.rownd.android.util.AuthenticatedApiClient
import io.rownd.android.util.InvalidRefreshTokenException
import io.rownd.android.util.NetworkConnectionFailureException
Expand Down Expand Up @@ -96,6 +97,11 @@ class AuthRepo @Inject constructor() {
idToken = idToken,
intent = intent
)

if (stateRepo.state.value.user.authLevel == AuthLevel.Instant) {
tokenRequest.instantUserId = stateRepo.state.value.user.data["user_id"]?.toString()
}

return fetchTokenAsync(tokenRequest, intent, type).await()
}

Expand Down
32 changes: 32 additions & 0 deletions android/src/main/java/io/rownd/android/models/repos/StateRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
import androidx.datastore.dataStoreFile
import io.opentelemetry.api.trace.StatusCode
import io.rownd.android.Rownd
import io.rownd.android.RowndSignInIntent
import io.rownd.android.RowndSignInJsOptions
import io.rownd.android.RowndSignInLoginStep
import io.rownd.android.RowndSignInOptions
import io.rownd.android.models.Action
import io.rownd.android.models.State
import io.rownd.android.models.Store
Expand All @@ -21,9 +23,12 @@ import io.rownd.android.models.domain.AuthState
import io.rownd.android.models.domain.SignInState
import io.rownd.android.models.domain.User
import io.rownd.android.util.AppLifecycleListener
import io.rownd.android.util.AuthLevel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -149,6 +154,8 @@ class StateRepo @Inject constructor() {
userRepo.loadUserAsync().await()
}

tmpForceInstantUserConversionIfRequested(CoroutineScope(Dispatchers.IO))

// Persist all state updates to cache when changes occur
store.stateAsStateFlow().collect {
val updatedState = it
Expand All @@ -161,6 +168,31 @@ class StateRepo @Inject constructor() {
return store
}

private fun tmpForceInstantUserConversionIfRequested(scope: CoroutineScope) {
if (!Rownd.config.forceInstantUserConversion) {
return
}

scope.launch {
Rownd.state
.map { it.auth.isAuthenticated to it.user }
.distinctUntilChanged()
.collect { (isAuthenticated, user) ->
if (
isAuthenticated &&
user.authLevel == AuthLevel.Instant
) {
val signInOptions = RowndSignInOptions(
intent = RowndSignInIntent.SignUp,
title = "Add a sign-in method",
subtitle = "To ensure you can always access your account, please add a sign-in method."
)
Rownd.requestSignIn(signInOptions)
}
}
}
}

val state = store.stateAsStateFlow()

fun getStore(): Store<GlobalState, StateAction> {
Expand Down
16 changes: 16 additions & 0 deletions android/src/main/java/io/rownd/android/util/AuthLevel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.rownd.android.util

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
enum class AuthLevel {
@SerialName("instant")
Instant,
@SerialName("guest")
Guest,
@SerialName("unverified")
Unverified,
@SerialName("verified")
Verified
}
22 changes: 16 additions & 6 deletions android/src/main/java/io/rownd/android/views/RowndWebView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ class RowndWebViewClient(private val webView: RowndWebView, private val context:
private var timeout: Boolean = true

init {

CoroutineScope(Dispatchers.IO).launch {
delay(20000)
if (timeout) {
Expand Down Expand Up @@ -294,6 +293,7 @@ class RowndWebViewClient(private val webView: RowndWebView, private val context:
}

setFeatureFlagJs()
setDebugFlags()

view.setLayerType(WebView.LAYER_TYPE_HARDWARE, null)

Expand Down Expand Up @@ -361,6 +361,16 @@ class RowndWebViewClient(private val webView: RowndWebView, private val context:
evaluateJavascript(code)
}

private fun setDebugFlags() {
if (Rownd.config.enableDebugMode) {
evaluateJavascript("""
if (rownd?.setLogLevel) {
rownd.setLogLevel('default', 'debug');
}
""".trimIndent())
}
}

private fun handleScriptReturn(value: String) {
Log.d("Rownd.hub", value)
}
Expand Down Expand Up @@ -488,9 +498,9 @@ class RowndJavascriptInterface constructor(
val authChallengeMessage = (interopMessage as AuthChallengeInitiatedMessage)
Rownd.store.dispatch(
StateAction.SetAuth(
AuthState(
parentWebView.rowndClient.stateRepo.state.value.auth.copy(
challengeId = authChallengeMessage.payload.challengeId,
userIdentifier = authChallengeMessage.payload.userIdentifier
userIdentifier = authChallengeMessage.payload.userIdentifier,
)
)
)
Expand All @@ -500,9 +510,9 @@ class RowndJavascriptInterface constructor(
parentWebView.rowndClient.store.currentState.auth.let {
Rownd.store.dispatch(
StateAction.SetAuth(
AuthState(
accessToken = it.accessToken,
refreshToken = it.refreshToken,
it.copy(
challengeId = null,
userIdentifier = null,
)
)
)
Expand Down