[App] Fix cookie persistence.

This commit is contained in:
Kuba Szczodrzyński 2023-03-24 10:56:35 +01:00
parent 31b569b02e
commit beff1b6460
No known key found for this signature in database
GPG Key ID: 43037AC62A600562
5 changed files with 75 additions and 30 deletions

View File

@ -29,11 +29,12 @@ class SignatureInterceptor(val app: App) : Interceptor {
return chain.proceed( return chain.proceed(
request.newBuilder() request.newBuilder()
.header("X-ApiKey", app.config.apiKeyCustom?.takeValue() ?: API_KEY) .header("X-ApiKey", app.config.apiKeyCustom?.takeValue() ?: API_KEY)
.header("X-AppVersion", BuildConfig.VERSION_CODE.toString())
.header("X-Timestamp", timestamp.toString())
.header("X-Signature", sign(timestamp, body, url))
.header("X-AppBuild", BuildConfig.BUILD_TYPE) .header("X-AppBuild", BuildConfig.BUILD_TYPE)
.header("X-AppFlavor", BuildConfig.FLAVOR) .header("X-AppFlavor", BuildConfig.FLAVOR)
.header("X-AppVersion", BuildConfig.VERSION_CODE.toString())
.header("X-DeviceId", app.deviceId)
.header("X-Signature", sign(timestamp, body, url))
.header("X-Timestamp", timestamp.toString())
.build()) .build())
} }

View File

@ -15,6 +15,7 @@ import android.text.style.CharacterStyle
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import androidx.annotation.PluralsRes import androidx.annotation.PluralsRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.holder.StringHolder
@ -160,6 +161,11 @@ fun CharSequence?.asBoldSpannable(): Spannable {
spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable return spannable
} }
fun CharSequence?.asUnderlineSpannable(): Spannable {
val spannable = SpannableString(this)
spannable.setSpan(UnderlineSpan(), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
fun CharSequence.asSpannable( fun CharSequence.asSpannable(
vararg spans: CharacterStyle, vararg spans: CharacterStyle,
substring: CharSequence? = null, substring: CharSequence? = null,

View File

@ -5,8 +5,20 @@
package pl.szczodrzynski.edziennik.network.cookie package pl.szczodrzynski.edziennik.network.cookie
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.HttpUrl
class DumbCookie(var cookie: Cookie) { class DumbCookie(var cookie: Cookie) {
companion object {
fun deserialize(key: String, value: String): DumbCookie? {
val (domain, _) = key.split('|', limit = 2)
val url = HttpUrl.Builder()
.scheme("https")
.host(domain)
.build()
val cookie = Cookie.parse(url, value) ?: return null
return DumbCookie(cookie)
}
}
constructor(domain: String, name: String, value: String, expiresAt: Long? = null) : this( constructor(domain: String, name: String, value: String, expiresAt: Long? = null) : this(
Cookie.Builder() Cookie.Builder()
@ -45,4 +57,9 @@ class DumbCookie(var cookie: Cookie) {
hash = 31 * hash + cookie.domain().hashCode() hash = 31 * hash + cookie.domain().hashCode()
return hash return hash
} }
fun serialize(): Pair<String, String> {
val key = cookie.domain() + "|" + cookie.name()
return key to cookie.toString()
}
} }

View File

@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.network.cookie package pl.szczodrzynski.edziennik.network.cookie
import android.content.Context import android.content.Context
import androidx.core.content.edit
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -26,22 +27,31 @@ class DumbCookieJar(
) : CookieJar { ) : CookieJar {
private val prefs = context.getSharedPreferences("cookies", Context.MODE_PRIVATE) private val prefs = context.getSharedPreferences("cookies", Context.MODE_PRIVATE)
val sessionCookies = mutableSetOf<DumbCookie>() private val sessionCookies = mutableSetOf<DumbCookie>()
private val savedCookies = mutableSetOf<DumbCookie>()
init {
prefs.all.forEach { (key, value) ->
if (value !is String)
return@forEach
sessionCookies.add(DumbCookie.deserialize(key, value) ?: return@forEach)
}
}
private fun save(dc: DumbCookie) { private fun save(dc: DumbCookie) {
sessionCookies.remove(dc) sessionCookies.remove(dc)
sessionCookies.add(dc) sessionCookies.add(dc)
if (dc.cookie.persistent() || persistAll) { if (dc.cookie.persistent() || persistAll) {
savedCookies.remove(dc) prefs.edit {
savedCookies.add(dc) val (key, value) = dc.serialize()
putString(key, value)
}
} }
} }
private fun delete(vararg toRemove: DumbCookie) { private fun delete(vararg toRemove: DumbCookie) {
sessionCookies.removeAll(toRemove) sessionCookies.removeAll(toRemove)
savedCookies.removeAll(toRemove)
} }
override fun saveFromResponse(url: HttpUrl?, cookies: List<Cookie>) { override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {
for (cookie in cookies) { for (cookie in cookies) {
val dc = DumbCookie(cookie) val dc = DumbCookie(cookie)
save(dc) save(dc)
@ -54,6 +64,10 @@ class DumbCookieJar(
}.map { it.cookie } }.map { it.cookie }
} }
fun getAllDomains(): List<Cookie> {
return sessionCookies.map { it.cookie }
}
fun get(domain: String, name: String): String? { fun get(domain: String, name: String): String? {
return sessionCookies.firstOrNull { return sessionCookies.firstOrNull {
it.domainMatches(domain) && it.cookie.name() == name it.domainMatches(domain) && it.cookie.name() == name
@ -84,7 +98,7 @@ class DumbCookieJar(
fun getAll(domain: String): Map<String, String> { fun getAll(domain: String): Map<String, String> {
return sessionCookies.filter { return sessionCookies.filter {
it.domainMatches(domain) it.domainMatches(domain)
}.map { it.cookie.name() to it.cookie.value() }.toMap() }.associate { it.cookie.name() to it.cookie.value() }
} }
fun remove(domain: String, name: String) { fun remove(domain: String, name: String) {

View File

@ -181,26 +181,33 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
startCoroutineTimer(500L, 300L) { startCoroutineTimer(500L, 300L) {
val text = app.cookieJar.sessionCookies val text = app.cookieJar.getAllDomains()
.map { it.cookie } .sortedBy { it.domain() }
.sortedBy { it.domain() } .groupBy { it.domain() }
.groupBy { it.domain() } .map { pair ->
.map { listOf(
listOf( pair.key.asBoldSpannable(),
it.key.asBoldSpannable(), ":\n",
":\n", pair.value
it.value .sortedBy { it.name() }
.sortedBy { it.name() } .map { cookie ->
.map { listOf(
listOf( " ",
" ", if (cookie.persistent())
it.name(), cookie.name()
"=", .asUnderlineSpannable()
it.value().decode().take(40).asItalicSpannable().asColoredSpannable(colorSecondary) else
).concat("") cookie.name(),
}.concat("\n") "=",
).concat("") cookie.value()
}.concat("\n\n") .decode()
.take(40)
.asItalicSpannable()
.asColoredSpannable(colorSecondary),
).concat("")
}.concat("\n")
).concat("")
}.concat("\n\n")
b.cookies.text = text b.cookies.text = text
} }