Migrate cookies store to CookieManager backend

This commit is contained in:
tarsin committed 2023-06-08 16:11:48 +08:00
1 parent ad04681460
commit 55b3753e66
10 files changed
+81 -389

No files matched your search

@@ -37,6 +37,7 @@ import com.hippo.ehviewer.dailycheck.checkDawn
import com.hippo.ehviewer.dao.EhDatabase import com.hippo.ehviewer.dao.EhDatabase
import com.hippo.ehviewer.download.DownloadManager import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.legacy.cleanObsoleteCache import com.hippo.ehviewer.legacy.cleanObsoleteCache
import com.hippo.ehviewer.legacy.migrateCookies
import com.hippo.ehviewer.okhttp.cache import com.hippo.ehviewer.okhttp.cache
import com.hippo.ehviewer.okhttp.httpClient import com.hippo.ehviewer.okhttp.httpClient
import com.hippo.ehviewer.ui.keepNoMediaFileStatus import com.hippo.ehviewer.ui.keepNoMediaFileStatus
@@ -76,6 +77,9 @@ class EhApplication : Application(), ImageLoaderFactory {
} }
} }
launchIO { launchIO {
launchIO {
migrateCookies()
}
launchIO { launchIO {
EhTagDatabase.update() EhTagDatabase.update()
} }
@@ -15,45 +15,42 @@
*/ */
package com.hippo.ehviewer.client package com.hippo.ehviewer.client
import com.hippo.ehviewer.network.CookieDatabase import android.webkit.CookieManager
import com.hippo.ehviewer.network.CookieSet
import eu.kanade.tachiyomi.util.lang.launchIO
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import splitties.init.appCtx
import java.util.Collections
import java.util.regex.Pattern import java.util.regex.Pattern
object EhCookieStore : CookieJar { object EhCookieStore : CookieJar {
private val db: CookieDatabase = CookieDatabase(appCtx) private val manager = CookieManager.getInstance()
private val map: MutableMap<String, CookieSet> = db.allCookies fun signOut() = manager.removeAllCookies(null)
fun contains(url: HttpUrl, name: String) = get(url).any { it.name == name }
fun signOut() { fun get(url: HttpUrl): List<Cookie> {
clear() val cookies = manager.getCookie(url.toString())
return if (cookies != null && cookies.isNotEmpty()) {
cookies.split(";").mapNotNull { Cookie.parse(url, it) }.filterNot { it.name == KEY_UTMP_NAME }
} else {
emptyList()
}
} }
fun hasSignedIn(): Boolean { fun hasSignedIn(): Boolean {
val url = EhUrl.HOST_E.toHttpUrl() val url = EhUrl.HOST_E.toHttpUrl()
return contains(url, KEY_IPB_MEMBER_ID) && return contains(url, KEY_IPB_MEMBER_ID) && contains(url, KEY_IPB_PASS_HASH)
contains(url, KEY_IPB_PASS_HASH)
} }
const val KEY_IPB_MEMBER_ID = "ipb_member_id" const val KEY_IPB_MEMBER_ID = "ipb_member_id"
const val KEY_IPB_PASS_HASH = "ipb_pass_hash" const val KEY_IPB_PASS_HASH = "ipb_pass_hash"
const val KEY_IGNEOUS = "igneous" const val KEY_IGNEOUS = "igneous"
const val KEY_SETTINGS_PROFILE = "sp" const val KEY_SETTINGS_PROFILE = "sp"
const val KEY_STAR = "star" private const val KEY_STAR = "star"
private const val KEY_CONTENT_WARNING = "nw" private const val KEY_CONTENT_WARNING = "nw"
private const val CONTENT_WARNING_NOT_SHOW = "1" private const val CONTENT_WARNING_NOT_SHOW = "1"
private val sTipsCookie: Cookie = Cookie.Builder() private const val KEY_UTMP_NAME = "__utmp"
.name(KEY_CONTENT_WARNING) private val sTipsCookie: Cookie = Cookie.Builder().name(KEY_CONTENT_WARNING).value(CONTENT_WARNING_NOT_SHOW).domain(EhUrl.DOMAIN_E).path("/").expiresAt(Long.MAX_VALUE).build()
.value(CONTENT_WARNING_NOT_SHOW)
.domain(EhUrl.DOMAIN_E)
.path("/")
.expiresAt(Long.MAX_VALUE)
.build()
fun newCookie( fun newCookie(
cookie: Cookie, cookie: Cookie,
@@ -87,64 +84,22 @@ object EhCookieStore : CookieJar {
return builder.build() return builder.build()
} }
fun copyCookie(domain: String, newDomain: String, name: String, path: String = "/") { fun copyNecessaryCookies() {
val cookie = map[domain]?.get(name, domain, path) val cookie = get(EhUrl.HOST_E.toHttpUrl()).filter { it.name == KEY_STAR || it.name == KEY_IPB_MEMBER_ID || it.name == KEY_IPB_PASS_HASH || it.name == KEY_IGNEOUS }
cookie?.let { addCookie(newCookie(it, newDomain)) } cookie.forEach { manager.setCookie(EhUrl.HOST_EX, it.toString()) }
} }
fun deleteCookie(url: HttpUrl, name: String) { fun deleteCookie(url: HttpUrl, name: String) {
val deletedCookie = Cookie.Builder() val deletedCookie = Cookie.Builder().name(name).value("deleted").domain(url.host).expiresAt(0).build()
.name(name) manager.setCookie(url.toString(), deletedCookie.toString())
.value("deleted")
.domain(url.host)
.expiresAt(0)
.build()
addCookie(deletedCookie)
} }
@Synchronized
fun addCookie(cookie: Cookie) { fun addCookie(cookie: Cookie) {
// For cookie database if (EhUrl.DOMAIN_E in cookie.domain) manager.setCookie(EhUrl.HOST_E, cookie.toString()) else manager.setCookie(EhUrl.DOMAIN_EX, cookie.toString())
var toAdd: Cookie? = null
var toUpdate: Cookie? = null
var toRemove: Cookie? = null
var set = map[cookie.domain]
if (set == null) {
set = CookieSet()
map[cookie.domain] = set
}
if (cookie.expiresAt <= System.currentTimeMillis()) {
toRemove = set.remove(cookie)
// If the cookie is not persistent, it's not in database
if (toRemove != null && !toRemove.persistent) {
toRemove = null
}
} else {
toAdd = cookie
toUpdate = set.add(cookie)
// If the cookie is not persistent, it's not in database
if (!toAdd.persistent) toAdd = null
if (toUpdate != null && !toUpdate.persistent) toUpdate = null
// Remove the cookie if it updates to null
if (toAdd == null && toUpdate != null) {
toRemove = toUpdate
toUpdate = null
}
}
if (toRemove != null) {
db.remove(toRemove)
}
if (toAdd != null) {
if (toUpdate != null) {
db.update(toUpdate, toAdd)
} else {
db.add(toAdd)
}
}
} }
fun getCookieHeader(url: HttpUrl): String { fun getCookieHeader(url: HttpUrl): String {
val cookies = getCookies(url) val cookies = get(url)
val cookieHeader = StringBuilder() val cookieHeader = StringBuilder()
var i = 0 var i = 0
val size = cookies.size val size = cookies.size
@@ -159,56 +114,8 @@ object EhCookieStore : CookieJar {
return cookieHeader.toString() return cookieHeader.toString()
} }
@Synchronized // See https://github.com/Ehviewer-Overhauled/Ehviewer/issues/873
fun getCookies(url: HttpUrl): List<Cookie> { override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) = cookies.filterNot { it.name == KEY_UTMP_NAME }.forEach { manager.setCookie(url.toString(), it.toString()) }
val accepted: MutableList<Cookie> = ArrayList()
val expired: MutableList<Cookie> = ArrayList()
for ((domain, cookieSet) in map) {
if (domainMatch(url, domain)) {
cookieSet[url, accepted, expired]
}
}
for (cookie in expired) {
if (cookie.persistent) {
db.remove(cookie)
}
}
// RFC 6265 Section-5.4 step 2, sort the cookie-list
// Cookies with longer paths are listed before cookies with shorter paths.
// Ignore creation-time, we don't store them.
accepted.sortWith { o1: Cookie, o2: Cookie -> o2.path.length - o1.path.length }
return accepted
}
fun contains(url: HttpUrl, name: String?): Boolean {
for (cookie in getCookies(url)) {
if (cookie.name == name) {
return true
}
}
return false
}
/**
* Remove all cookies in this `CookieRepository`.
*/
@Synchronized
fun clear() {
map.clear()
launchIO {
db.clear()
}
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
for (cookie in cookies) {
// See https://github.com/Ehviewer-Overhauled/Ehviewer/issues/873
if (cookie.name != "__utmp") {
addCookie(cookie)
}
}
}
/** /**
* Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation * Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation
@@ -221,8 +128,7 @@ object EhCookieStore : CookieJar {
* addresses nor hostnames; they will be verified as IP addresses (which is a more strict * addresses nor hostnames; they will be verified as IP addresses (which is a more strict
* verification). * verification).
*/ */
private val VERIFY_AS_IP_ADDRESS = private val VERIFY_AS_IP_ADDRESS = Pattern.compile("([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)")
Pattern.compile("([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)")
/** /**
* Returns true if `host` is not a host name and might be an IP address. * Returns true if `host` is not a host name and might be an IP address.
@@ -238,32 +144,19 @@ object EhCookieStore : CookieJar {
return if (urlHost == domain) { return if (urlHost == domain) {
true // As in 'example.com' matching 'example.com'. true // As in 'example.com' matching 'example.com'.
} else { } else {
urlHost.endsWith(domain!!) && urlHost.endsWith(domain!!) && urlHost[urlHost.length - domain.length - 1] == '.' && !verifyAsIpAddress(urlHost)
urlHost[urlHost.length - domain.length - 1] == '.' && !verifyAsIpAddress(
urlHost,
)
} }
// As in 'example.com' matching 'www.example.com'. // As in 'example.com' matching 'www.example.com'.
} }
override fun loadForRequest(url: HttpUrl): List<Cookie> { override fun loadForRequest(url: HttpUrl): List<Cookie> {
val cookies = getCookies(url)
val checkTips = domainMatch(url, EhUrl.DOMAIN_E) val checkTips = domainMatch(url, EhUrl.DOMAIN_E)
return if (checkTips) { return get(url).run {
val result: MutableList<Cookie> = ArrayList(cookies.size + 1) if (checkTips) {
// Add all but skip some filterNot { it.name == KEY_CONTENT_WARNING }.toMutableList().apply { add(sTipsCookie) }
for (cookie in cookies) { } else {
val name = cookie.name this
if (KEY_CONTENT_WARNING == name) {
continue
}
result.add(cookie)
} }
// Add some
result.add(sTipsCookie)
Collections.unmodifiableList(result)
} else {
cookies
} }
} }
} }
@@ -0,0 +1,37 @@
package com.hippo.ehviewer.legacy
import arrow.fx.coroutines.release
import arrow.fx.coroutines.resource
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.dao.Cookie
import com.hippo.ehviewer.dao.CookiesDatabase
import splitties.arch.room.roomDb
import splitties.init.appCtx
private const val legacyCookiesDB = "okhttp3-cookie.db"
private fun Cookie.toOkHttp3Cookie(): okhttp3.Cookie {
return okhttp3.Cookie.Builder().apply {
name(name)
value(value)
expiresAt(expiresAt)
if (hostOnly) hostOnlyDomain(domain) else domain(domain)
path(path)
if (secure) secure()
if (httpOnly) httpOnly()
}.build()
}
suspend fun migrateCookies() {
if (legacyCookiesDB !in appCtx.databaseList()) return
resource {
roomDb<CookiesDatabase>(legacyCookiesDB)
} release {
it.close()
appCtx.deleteDatabase(legacyCookiesDB)
} use { database ->
database.cookiesDao().list().forEach {
EhCookieStore.addCookie(it.toOkHttp3Cookie())
}
}
}
@@ -1,91 +0,0 @@
/*
* Copyright 2017 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.network
import android.content.Context
import com.hippo.ehviewer.dao.Cookie
import com.hippo.ehviewer.dao.CookiesDatabase
import splitties.arch.room.roomDb
import okhttp3.Cookie as OkHttpCookie
class CookieDatabase(context: Context) {
private val cookiesList by lazy {
val now = System.currentTimeMillis()
db.cookiesDao().list().mapNotNull {
it.takeUnless { !it.persistent || it.expiresAt <= now } ?: run {
db.cookiesDao().delete(it)
null
}
}.toMutableList()
}
private val db = roomDb<CookiesDatabase>("okhttp3-cookie.db")
val allCookies by lazy {
hashMapOf<String, CookieSet>().also { map ->
cookiesList.map { it.toOkHttp3Cookie() }.forEach {
val set = map[it.domain] ?: CookieSet().apply { map[it.domain] = this }
set.add(it)
}
}
}
private fun findCookieWithOkHttpCookies(cookie: OkHttpCookie): Cookie? {
return cookiesList.find { it.name == cookie.name && it.domain == cookie.domain && it.value == cookie.value }
}
fun add(cookie: OkHttpCookie) {
val c = cookie.toCookie()
c.id = db.cookiesDao().insert(c)
cookiesList.add(c)
}
fun update(from: OkHttpCookie, to: OkHttpCookie) {
val origin = findCookieWithOkHttpCookies(from) ?: return
val new = to.toCookie(origin.id)
cookiesList.remove(origin)
cookiesList.add(new)
db.cookiesDao().update(new)
}
fun remove(cookie: OkHttpCookie) {
val origin = findCookieWithOkHttpCookies(cookie) ?: return
db.cookiesDao().delete(origin)
cookiesList.remove(origin)
}
fun clear() {
db.clearAllTables()
cookiesList.clear()
}
}
fun Cookie.toOkHttp3Cookie(): OkHttpCookie {
return OkHttpCookie.Builder().apply {
name(name)
value(value)
expiresAt(expiresAt)
if (hostOnly) hostOnlyDomain(domain) else domain(domain)
path(path)
if (secure) secure()
if (httpOnly) httpOnly()
}.build()
}
private fun OkHttpCookie.toCookie(id: Long? = null): Cookie {
return Cookie(
name, value, expiresAt, domain, path, secure, httpOnly, persistent, hostOnly, id,
)
}
@@ -1,68 +0,0 @@
/*
* Copyright 2017 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.network
import okhttp3.Cookie
import okhttp3.HttpUrl
class CookieSet {
private val map: MutableMap<Key, Cookie> = HashMap()
/**
* Adds a cookie to this `CookieSet`.
* Returns a previous cookie with
* the same name, domain and path or `null`.
*/
fun add(cookie: Cookie): Cookie? {
return map.put(Key(cookie), cookie)
}
/**
* Removes a cookie with the same name,
* domain and path as the cookie.
* Returns the removed cookie or `null`.
*/
fun remove(cookie: Cookie): Cookie? {
return map.remove(Key(cookie))
}
/**
* Get cookies for the url. Fill `accepted` and `expired`.
*/
operator fun get(url: HttpUrl, accepted: MutableList<Cookie>, expired: MutableList<Cookie>) {
val now = System.currentTimeMillis()
val iterator = map.entries.iterator()
while (iterator.hasNext()) {
val cookie = iterator.next().value
if (cookie.expiresAt <= now) {
iterator.remove()
expired.add(cookie)
} else if (cookie.matches(url)) {
accepted.add(cookie)
}
}
}
fun get(name: String, domain: String, path: String) = map[Key(name, domain, path)]
internal data class Key(
val name: String,
val domain: String,
val path: String,
) {
constructor(cookie: Cookie) : this(cookie.name, cookie.domain, cookie.path)
}
}
@@ -21,7 +21,7 @@ suspend fun postLogin() = coroutineScope {
runCatching { runCatching {
// For the `star` cookie // For the `star` cookie
EhEngine.getNews(false) EhEngine.getNews(false)
EhCookieStore.copyCookie(EhUrl.DOMAIN_E, EhUrl.DOMAIN_EX, EhCookieStore.KEY_STAR) EhCookieStore.copyNecessaryCookies()
// Sad panda check // Sad panda check
Settings.gallerySite = EhUrl.SITE_EX Settings.gallerySite = EhUrl.SITE_EX
@@ -21,8 +21,6 @@ import com.hippo.ehviewer.ui.SELECT_SITE_ROUTE_NAME
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withNonCancellableContext import eu.kanade.tachiyomi.util.lang.withNonCancellableContext
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@@ -34,63 +32,24 @@ fun WebviewSignInScreen() {
val client = remember { val client = remember {
object : AccompanistWebViewClient() { object : AccompanistWebViewClient() {
private var present = false private var present = false
fun parseCookies(url: HttpUrl?, cookieStrings: String?): List<Cookie> {
if (cookieStrings == null) {
return emptyList()
}
var cookies: MutableList<Cookie>? = null
val pieces =
cookieStrings.split(";".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
for (piece in pieces) {
val cookie = Cookie.parse(url!!, piece) ?: continue
if (cookies == null) {
cookies = ArrayList()
}
cookies.add(cookie)
}
return cookies ?: emptyList()
}
fun addCookie(domain: String, cookie: Cookie) {
EhCookieStore.addCookie(
EhCookieStore.newCookie(
cookie,
domain,
forcePersistent = true,
forceLongLive = true,
forceNotHostOnly = true,
),
)
}
override fun onPageFinished(view: WebView, url: String?) { override fun onPageFinished(view: WebView, url: String?) {
if (present) { if (present) {
view.destroy() view.destroy()
return return
} }
val httpUrl = url?.toHttpUrl() ?: return
val cookieString = CookieManager.getInstance().getCookie(EhUrl.HOST_E)
val cookies = parseCookies(httpUrl, cookieString)
var getId = false var getId = false
var getHash = false var getHash = false
for (cookie in cookies) { EhCookieStore.loadForRequest(EhUrl.HOST_E.toHttpUrl()).forEach {
if (EhCookieStore.KEY_IPB_MEMBER_ID == cookie.name) { if (EhCookieStore.KEY_IPB_MEMBER_ID == it.name) {
getId = true getId = true
} else if (EhCookieStore.KEY_IPB_PASS_HASH == cookie.name) { } else if (EhCookieStore.KEY_IPB_PASS_HASH == it.name) {
getHash = true getHash = true
} }
} }
if (getId && getHash) { if (getId && getHash) {
present = true present = true
coroutineScope.launchIO { coroutineScope.launchIO {
val canEx = withNonCancellableContext { val canEx = withNonCancellableContext { postLogin() }
cookies.forEach {
addCookie(EhUrl.DOMAIN_EX, it)
addCookie(EhUrl.DOMAIN_E, it)
}
postLogin()
}
withUIContext { navController.navigate(if (canEx) SELECT_SITE_ROUTE_NAME else FINISH_ROUTE_NAME) } withUIContext { navController.navigate(if (canEx) SELECT_SITE_ROUTE_NAME else FINISH_ROUTE_NAME) }
} }
} }
@@ -91,8 +91,8 @@ fun EhScreen() {
title = stringResource(id = R.string.account_name), title = stringResource(id = R.string.account_name),
summary = Settings.displayName ?: touristMode, summary = Settings.displayName ?: touristMode,
) { ) {
val eCookies = EhCookieStore.getCookies(EhUrl.HOST_E.toHttpUrl()) val eCookies = EhCookieStore.loadForRequest(EhUrl.HOST_E.toHttpUrl())
val exCookies = EhCookieStore.getCookies(EhUrl.HOST_EX.toHttpUrl()) val exCookies = EhCookieStore.loadForRequest(EhUrl.HOST_EX.toHttpUrl())
var ipbMemberId: String? = null var ipbMemberId: String? = null
var ipbPassHash: String? = null var ipbPassHash: String? = null
var igneous: String? = null var igneous: String? = null
@@ -1,7 +1,6 @@
package com.hippo.ehviewer.ui.settings package com.hippo.ehviewer.ui.settings
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.webkit.CookieManager
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -12,16 +11,13 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import com.google.accompanist.web.WebView import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState import com.google.accompanist.web.rememberWebViewState
import com.hippo.ehviewer.R import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.ui.LocalNavController import com.hippo.ehviewer.ui.LocalNavController
import okhttp3.HttpUrl.Companion.toHttpUrl
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Composable @Composable
@@ -52,16 +48,5 @@ fun MyTagsScreen() {
} }
}, },
) )
SideEffect {
CookieManager.getInstance().apply {
flush()
removeAllCookies(null)
removeSessionCookies(null)
// Copy cookies from okhttp cookie store to CookieManager
EhCookieStore.getCookies(url.toHttpUrl()).forEach {
setCookie(url, it.toString())
}
}
}
} }
} }
@@ -1,7 +1,6 @@
package com.hippo.ehviewer.ui.settings package com.hippo.ehviewer.ui.settings
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.webkit.CookieManager
import android.webkit.WebView import android.webkit.WebView
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -29,8 +28,6 @@ import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhCookieStore.KEY_SETTINGS_PROFILE import com.hippo.ehviewer.client.EhCookieStore.KEY_SETTINGS_PROFILE
import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.ui.LocalNavController import com.hippo.ehviewer.ui.LocalNavController
import eu.kanade.tachiyomi.util.lang.launchIO
import okhttp3.Cookie
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
private const val applyJs = "javascript:(function(){var apply = document.getElementById(\"apply\").children[0];apply.click();})();" private const val applyJs = "javascript:(function(){var apply = document.getElementById(\"apply\").children[0];apply.click();})();"
@@ -81,33 +78,9 @@ fun UConfigScreen() {
val applyTip = stringResource(id = R.string.apply_tip) val applyTip = stringResource(id = R.string.apply_tip)
LaunchedEffect(Unit) { snackbarHostState.showSnackbar(applyTip) } LaunchedEffect(Unit) { snackbarHostState.showSnackbar(applyTip) }
DisposableEffect(Unit) { DisposableEffect(Unit) {
CookieManager.getInstance().apply {
flush()
removeAllCookies(null)
removeSessionCookies(null)
// Copy cookies from okhttp cookie store to CookieManager
EhCookieStore.getCookies(url.toHttpUrl()).forEach {
setCookie(url, it.toString())
}
}
onDispose { onDispose {
// Put cookies back to okhttp cookie store EhCookieStore.deleteCookie(EhUrl.host.toHttpUrl(), KEY_SETTINGS_PROFILE)
val cookiesString = CookieManager.getInstance().getCookie(url)
if (cookiesString.isNotBlank()) {
val hostUrl = EhUrl.host.toHttpUrl()
launchIO {
EhCookieStore.deleteCookie(hostUrl, KEY_SETTINGS_PROFILE)
// The cookies saved in the uconfig page should not be shared between e and ex
for (header in cookiesString.split(";".toRegex()).dropLastWhile { it.isEmpty() }) {
Cookie.parse(hostUrl, header)?.let {
EhCookieStore.addCookie(longLive(it))
}
}
}
}
} }
} }
} }
} }
private fun longLive(cookie: Cookie) = Cookie.Builder().name(cookie.name).value(cookie.value).domain(cookie.domain).path(cookie.path).expiresAt(Long.MAX_VALUE).build()