From dc4aece27202724cba8ebdaa2d04c1acc07797a7 Mon Sep 17 00:00:00 2001 From: tarsin Date: Sat, 14 Jan 2023 10:21:59 +0800 Subject: [PATCH] Inline EhCookieStore supertype --- .../hippo/ehviewer/client/EhCookieStore.kt | 200 +++++++++++++++--- .../com/hippo/network/CookieRepository.kt | 181 ---------------- 2 files changed, 174 insertions(+), 207 deletions(-) delete mode 100644 app/src/main/java/com/hippo/network/CookieRepository.kt diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhCookieStore.kt b/app/src/main/java/com/hippo/ehviewer/client/EhCookieStore.kt index 8d6c7f561..549f9c9a5 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhCookieStore.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/EhCookieStore.kt @@ -16,13 +16,19 @@ package com.hippo.ehviewer.client import com.hippo.ehviewer.EhApplication -import com.hippo.network.CookieRepository +import com.hippo.network.CookieDatabase +import com.hippo.network.CookieSet import okhttp3.Cookie +import okhttp3.CookieJar import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import java.util.Collections +import java.util.regex.Pattern + +object EhCookieStore : CookieJar { + private val db: CookieDatabase = CookieDatabase(EhApplication.application, "okhttp3-cookie.db") + private val map: MutableMap = db.allCookies -object EhCookieStore : CookieRepository(EhApplication.application, "okhttp3-cookie.db") { fun signOut() { clear() } @@ -33,30 +39,6 @@ object EhCookieStore : CookieRepository(EhApplication.application, "okhttp3-cook contains(url, KEY_IPD_PASS_HASH) } - override fun loadForRequest(url: HttpUrl): List { - val cookies = super.loadForRequest(url) - val checkTips = domainMatch(url, EhUrl.DOMAIN_E) - return if (checkTips) { - val result: MutableList = ArrayList(cookies.size + 1) - // Add all but skip some - for (cookie in cookies) { - val name = cookie.name - if (EhConfig.KEY_CONTENT_WARNING == name) { - continue - } - if (EhConfig.KEY_UCONFIG == name) { - continue - } - result.add(cookie) - } - // Add some - result.add(sTipsCookie) - Collections.unmodifiableList(result) - } else { - cookies - } - } - const val KEY_IPD_MEMBER_ID = "ipb_member_id" const val KEY_IPD_PASS_HASH = "ipb_pass_hash" const val KEY_IGNEOUS = "igneous" @@ -96,4 +78,170 @@ object EhCookieStore : CookieRepository(EhApplication.application, "okhttp3-cook } return builder.build() } + + @Synchronized + fun addCookie(cookie: Cookie) { + // For cookie database + 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 { + val cookies = getCookies(url) + val cookieHeader = StringBuilder() + var i = 0 + val size = cookies.size + while (i < size) { + if (i > 0) { + cookieHeader.append("; ") + } + val cookie = cookies[i] + cookieHeader.append(cookie.name).append('=').append(cookie.value) + i++ + } + return cookieHeader.toString() + } + + @Synchronized + fun getCookies(url: HttpUrl): List { + val accepted: MutableList = ArrayList() + val expired: MutableList = 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() + db.clear() + } + + @Synchronized + fun close() { + db.close() + } + + override fun saveFromResponse(url: HttpUrl, cookies: List) { + for (cookie in cookies) { + addCookie(cookie) + } + } + + /** + * Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation + * of Android's private InetAddress#isNumeric API. + * + * + * This matches IPv6 addresses as a hex string containing at least one colon, and possibly + * including dots after the first colon. It matches IPv4 addresses as strings containing only + * decimal digits and dots. This pattern matches strings like "a:.23" and "54" that are neither IP + * addresses nor hostnames; they will be verified as IP addresses (which is a more strict + * verification). + */ + private val VERIFY_AS_IP_ADDRESS = + 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. + */ + private fun verifyAsIpAddress(host: String): Boolean { + return VERIFY_AS_IP_ADDRESS.matcher(host).matches() + } + + // okhttp3.Cookie.domainMatch(HttpUrl, String) + @JvmStatic + fun domainMatch(url: HttpUrl, domain: String?): Boolean { + val urlHost = url.host + return if (urlHost == domain) { + true // As in 'example.com' matching 'example.com'. + } else urlHost.endsWith(domain!!) + && urlHost[urlHost.length - domain.length - 1] == '.' && !verifyAsIpAddress( + urlHost + ) + // As in 'example.com' matching 'www.example.com'. + } + + override fun loadForRequest(url: HttpUrl): List { + val cookies = getCookies(url) + val checkTips = domainMatch(url, EhUrl.DOMAIN_E) + return if (checkTips) { + val result: MutableList = ArrayList(cookies.size + 1) + // Add all but skip some + for (cookie in cookies) { + val name = cookie.name + if (EhConfig.KEY_CONTENT_WARNING == name) { + continue + } + if (EhConfig.KEY_UCONFIG == name) { + continue + } + result.add(cookie) + } + // Add some + result.add(sTipsCookie) + Collections.unmodifiableList(result) + } else { + cookies + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/hippo/network/CookieRepository.kt b/app/src/main/java/com/hippo/network/CookieRepository.kt deleted file mode 100644 index 471de86f7..000000000 --- a/app/src/main/java/com/hippo/network/CookieRepository.kt +++ /dev/null @@ -1,181 +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.network - -import android.content.Context -import com.hippo.yorozuya.ObjectUtils -import okhttp3.Cookie -import okhttp3.CookieJar -import okhttp3.HttpUrl -import java.util.regex.Pattern - -open class CookieRepository(context: Context, name: String) : CookieJar { - private val db: CookieDatabase - private val map: MutableMap - - @Synchronized - fun addCookie(cookie: Cookie) { - // For cookie database - 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 { - val cookies = getCookies(url) - val cookieHeader = StringBuilder() - var i = 0 - val size = cookies.size - while (i < size) { - if (i > 0) { - cookieHeader.append("; ") - } - val cookie = cookies[i] - cookieHeader.append(cookie.name).append('=').append(cookie.value) - i++ - } - return cookieHeader.toString() - } - - @Synchronized - fun getCookies(url: HttpUrl): List { - val accepted: MutableList = ArrayList() - val expired: MutableList = 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 (ObjectUtils.equal(cookie.name, name)) { - return true - } - } - return false - } - - /** - * Remove all cookies in this `CookieRepository`. - */ - @Synchronized - fun clear() { - map.clear() - db.clear() - } - - @Synchronized - fun close() { - db.close() - } - - override fun saveFromResponse(url: HttpUrl, cookies: List) { - for (cookie in cookies) { - addCookie(cookie) - } - } - - override fun loadForRequest(url: HttpUrl): List { - return getCookies(url) - } - - companion object { - /** - * Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation - * of Android's private InetAddress#isNumeric API. - * - * - * This matches IPv6 addresses as a hex string containing at least one colon, and possibly - * including dots after the first colon. It matches IPv4 addresses as strings containing only - * decimal digits and dots. This pattern matches strings like "a:.23" and "54" that are neither IP - * addresses nor hostnames; they will be verified as IP addresses (which is a more strict - * verification). - */ - private val VERIFY_AS_IP_ADDRESS = - 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. - */ - private fun verifyAsIpAddress(host: String): Boolean { - return VERIFY_AS_IP_ADDRESS.matcher(host).matches() - } - - // okhttp3.Cookie.domainMatch(HttpUrl, String) - @JvmStatic - protected fun domainMatch(url: HttpUrl, domain: String?): Boolean { - val urlHost = url.host - return if (urlHost == domain) { - true // As in 'example.com' matching 'example.com'. - } else urlHost.endsWith(domain!!) - && urlHost[urlHost.length - domain.length - 1] == '.' && !verifyAsIpAddress( - urlHost - ) - // As in 'example.com' matching 'www.example.com'. - } - } - - init { - db = CookieDatabase(context, name) - map = db.allCookies - } -} \ No newline at end of file