[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(
request.newBuilder()
.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-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())
}

View File

@ -15,6 +15,7 @@ import android.text.style.CharacterStyle
import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import androidx.annotation.PluralsRes
import androidx.annotation.StringRes
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)
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(
vararg spans: CharacterStyle,
substring: CharSequence? = null,

View File

@ -5,8 +5,20 @@
package pl.szczodrzynski.edziennik.network.cookie
import okhttp3.Cookie
import okhttp3.HttpUrl
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(
Cookie.Builder()
@ -45,4 +57,9 @@ class DumbCookie(var cookie: Cookie) {
hash = 31 * hash + cookie.domain().hashCode()
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
import android.content.Context
import androidx.core.content.edit
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
@ -26,22 +27,31 @@ class DumbCookieJar(
) : CookieJar {
private val prefs = context.getSharedPreferences("cookies", Context.MODE_PRIVATE)
val sessionCookies = mutableSetOf<DumbCookie>()
private val savedCookies = mutableSetOf<DumbCookie>()
private val sessionCookies = 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) {
sessionCookies.remove(dc)
sessionCookies.add(dc)
if (dc.cookie.persistent() || persistAll) {
savedCookies.remove(dc)
savedCookies.add(dc)
prefs.edit {
val (key, value) = dc.serialize()
putString(key, value)
}
}
}
private fun delete(vararg toRemove: DumbCookie) {
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) {
val dc = DumbCookie(cookie)
save(dc)
@ -54,6 +64,10 @@ class DumbCookieJar(
}.map { it.cookie }
}
fun getAllDomains(): List<Cookie> {
return sessionCookies.map { it.cookie }
}
fun get(domain: String, name: String): String? {
return sessionCookies.firstOrNull {
it.domainMatches(domain) && it.cookie.name() == name
@ -84,7 +98,7 @@ class DumbCookieJar(
fun getAll(domain: String): Map<String, String> {
return sessionCookies.filter {
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) {

View File

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