From 805ba591efcd674f3faba3d0f58f8a0de9a70d2b Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Sun, 21 Jun 2026 11:08:46 -0700 Subject: [PATCH] poll cookie jar once per second while webview is active as a fallback --- .../derakkuma/ui/auth/AuthScreen.android.kt | 132 +++++++++--------- .../com/derakkuma/ui/auth/AuthScreen.ios.kt | 9 +- 2 files changed, 77 insertions(+), 64 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/com/derakkuma/ui/auth/AuthScreen.android.kt b/composeApp/src/androidMain/kotlin/com/derakkuma/ui/auth/AuthScreen.android.kt index fb3c387..bdace39 100644 --- a/composeApp/src/androidMain/kotlin/com/derakkuma/ui/auth/AuthScreen.android.kt +++ b/composeApp/src/androidMain/kotlin/com/derakkuma/ui/auth/AuthScreen.android.kt @@ -41,6 +41,8 @@ actual fun AuthScreen(onLoginSuccess: (AuthState) -> Unit, sessionExpired: Boole var handled by remember { mutableStateOf(false) } var showWebView by remember { mutableStateOf(false) } var navigating by remember { mutableStateOf(true) } + var validationInFlight by remember { mutableStateOf(false) } + var rejectedCookie by remember { mutableStateOf(null) } val scope = rememberCoroutineScope() val validationClient = remember { HttpClient(OkHttp) { followRedirects = false } } @@ -55,6 +57,73 @@ actual fun AuthScreen(onLoginSuccess: (AuthState) -> Unit, sessionExpired: Boole if (!handled) showWebView = true } + fun tryCompleteLoginFromCookieStore(url: String?, source: String) { + if (url == null || handled || validationInFlight) return + + if (url.contains("/error/")) { + println("[auth] landed on error page from $source: $url — not extracting cookies") + navigating = false + showWebView = true + return + } + + if (url.contains("common_auth/login")) { + navigating = false + showWebView = true + return + } + + if (!url.contains("maimaidx")) return + + val cookies = CookieManager.getInstance().getCookie(url) + ?: CookieManager.getInstance().getCookie(LOGIN_URL) + ?: return + + if (!cookies.contains("_t=")) return + if (cookies == rejectedCookie) return + + navigating = false + + // Also grab clal cookie from the AIME gateway for session refresh + val aimeCookies = CookieManager.getInstance().getCookie(AIME_DOMAIN) ?: "" + val clal = aimeCookies.split(";") + .map { it.trim() } + .firstOrNull { it.startsWith("clal=") } + ?.substringAfter("clal=") + ?: "" + + println("[auth] extracted maimaidx cookies from $source at $url: ${cookies.take(80)}...") + println("[auth] clal cookie: ${if (clal.isNotEmpty()) "${clal.take(20)}..." else "NOT FOUND"}") + + validationInFlight = true + scope.launch { + if (validateMaimaiCookie(validationClient, cookies)) { + handled = true + validationInFlight = false + onLoginSuccess( + AuthState( + cookie = cookies, + region = "international", + clalCookie = clal, + ), + ) + } else { + println("[auth] extracted cookie failed validation; showing WebView for login") + rejectedCookie = cookies + validationInFlight = false + navigating = false + showWebView = true + } + } + } + + LaunchedEffect(showWebView, handled) { + while (showWebView && !handled) { + delay(1000.milliseconds) + tryCompleteLoginFromCookieStore(LOGIN_URL, "cookiePoll") + } + } + Box(modifier = Modifier.fillMaxSize()) { // WebView — always present but invisible until auto-login fails or user needs to interact AndroidView( @@ -75,69 +144,6 @@ actual fun AuthScreen(onLoginSuccess: (AuthState) -> Unit, sessionExpired: Boole cookieManager.setAcceptThirdPartyCookies(this, true) webViewClient = object : WebViewClient() { - private var validationInFlight = false - private var rejectedCookie: String? = null - - private fun tryCompleteLoginFromCookieStore(url: String?, source: String) { - if (url == null || handled || validationInFlight) return - - if (url.contains("/error/")) { - println("[auth] landed on error page from $source: $url — not extracting cookies") - navigating = false - showWebView = true - return - } - - if (url.contains("common_auth/login")) { - navigating = false - showWebView = true - return - } - - if (!url.contains("maimaidx")) return - - val cookies = CookieManager.getInstance().getCookie(url) - ?: CookieManager.getInstance().getCookie(LOGIN_URL) - ?: return - - if (!cookies.contains("_t=")) return - if (cookies == rejectedCookie) return - - navigating = false - - // Also grab clal cookie from the AIME gateway for session refresh - val aimeCookies = CookieManager.getInstance().getCookie(AIME_DOMAIN) ?: "" - val clal = aimeCookies.split(";") - .map { it.trim() } - .firstOrNull { it.startsWith("clal=") } - ?.substringAfter("clal=") - ?: "" - - println("[auth] extracted maimaidx cookies from $source at $url: ${cookies.take(80)}...") - println("[auth] clal cookie: ${if (clal.isNotEmpty()) "${clal.take(20)}..." else "NOT FOUND"}") - - validationInFlight = true - scope.launch { - if (validateMaimaiCookie(validationClient, cookies)) { - handled = true - validationInFlight = false - onLoginSuccess( - AuthState( - cookie = cookies, - region = "international", - clalCookie = clal, - ), - ) - } else { - println("[auth] extracted cookie failed validation; showing WebView for login") - rejectedCookie = cookies - validationInFlight = false - navigating = false - showWebView = true - } - } - } - override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { tryCompleteLoginFromCookieStore(request?.url?.toString(), "shouldOverrideUrlLoading") return false diff --git a/composeApp/src/iosMain/kotlin/com/derakkuma/ui/auth/AuthScreen.ios.kt b/composeApp/src/iosMain/kotlin/com/derakkuma/ui/auth/AuthScreen.ios.kt index fa50857..07215dd 100644 --- a/composeApp/src/iosMain/kotlin/com/derakkuma/ui/auth/AuthScreen.ios.kt +++ b/composeApp/src/iosMain/kotlin/com/derakkuma/ui/auth/AuthScreen.ios.kt @@ -81,6 +81,13 @@ actual fun AuthScreen(onLoginSuccess: (AuthState) -> Unit, sessionExpired: Boole if (!handled) showWebView = true } + LaunchedEffect(showWebView, handled) { + while (showWebView && !handled) { + delay(1000.milliseconds) + delegate.tryCompleteLoginFromCookieStore(LOGIN_URL, "cookiePoll") + } + } + Box(modifier = Modifier.fillMaxSize()) { UIKitView( modifier = Modifier @@ -177,7 +184,7 @@ private class IosAuthNavigationDelegate( } } - private fun tryCompleteLoginFromCookieStore(url: String?, source: String) { + fun tryCompleteLoginFromCookieStore(url: String?, source: String) { if (url == null || authAccepted || validationInFlight) return if (url.contains("/error/")) { -- 2.51.2