Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24a31235 authored by Fahim Salam Chowdhury's avatar Fahim Salam Chowdhury 👽
Browse files

fix: Session cookie passing after successful resource finder

When user init the login flow, first app tries to retrieve the DAV
providers info by making DAV request via DavResourceFinder. In this
stage, no account is created, so inMemoryCookieStore is used. After
successful resource info retrieval then account is created & then
refreshed the collection via RefreshCollectionWorker. As previously only
inMemory cookieJar is used, the refreshCollection makes it's first
request without any cookie, which causes extra server headace.

To mitigate this, we need to persist the last inMemory cookies after
successful resource retrieval.
parent 6eb995b4
Loading
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright MURENA SAS 2024
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package at.bitfire.davdroid.network

interface CookieParser {

    fun cookiesAsString(): String
}
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ fun createCookieStore(context: Context? = null, account: Account? = null): Cooki
    val murenaAddressBookAccountType = context.getString(R.string.account_type_eelo_address_book)

    if (account.type in listOf(murenaAccountType, murenaAddressBookAccountType)) {
        return MurenaCookieStore(context, account)
        return PersistenceCookieStore(context, account)
    }

    return MemoryCookieStore()
+8 −0
Original line number Diff line number Diff line
@@ -347,4 +347,12 @@ class HttpClient private constructor(

    }

    fun getCookieAsString(): String {
        val cookieJar = okHttpClient.cookieJar
        if (cookieJar is CookieParser) {
            return cookieJar.cookiesAsString()
        }

        return ""
    }
}
+11 −2
Original line number Diff line number Diff line
@@ -4,19 +4,20 @@

package at.bitfire.davdroid.network

import at.bitfire.davdroid.settings.AccountSettings
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
import org.apache.commons.collections4.keyvalue.MultiKey
import org.apache.commons.collections4.map.HashedMap
import org.apache.commons.collections4.map.MultiKeyMap
import java.util.*
import java.util.LinkedList

/**
 * Primitive cookie store that stores cookies in a (volatile) hash map.
 * Will be sufficient for session cookies.
 */
class MemoryCookieStore: CookieJar {
class MemoryCookieStore : CookieJar, CookieParser {

    /**
     * Stored cookies. The multi-key consists of three parts: name, domain, and path.
@@ -56,4 +57,12 @@ class MemoryCookieStore: CookieJar {
        return cookies
    }

    override fun cookiesAsString(): String {
        if (storage.isEmpty) {
            return ""
        }

        return storage.values.joinToString(separator = AccountSettings.COOKIE_SEPARATOR)
    }

}
+3 −3
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl

class MurenaCookieStore(context: Context, private val account: Account): CookieJar {
class PersistenceCookieStore(context: Context, private val account: Account): CookieJar {

    private val accountManager = AccountManager.get(context.applicationContext)

@@ -51,13 +51,13 @@ class MurenaCookieStore(context: Context, private val account: Account): CookieJ
        }

        val cookieString = cookieMap.values.joinToString(separator = AccountSettings.COOKIE_SEPARATOR)
        accountManager.setUserData(account, AccountSettings.MURENA_COOKIE_KEY, cookieString)
        accountManager.setUserData(account, AccountSettings.COOKIE_KEY, cookieString)
    }

    private fun getCookieMap(url: HttpUrl): HashMap<String, Cookie> {
        val result = HashMap<String, Cookie>()

            val cookiesString = accountManager.getUserData(account, AccountSettings.MURENA_COOKIE_KEY)
            val cookiesString = accountManager.getUserData(account, AccountSettings.COOKIE_KEY)
                ?: return HashMap()

            val cookies = cookiesString.split(AccountSettings.COOKIE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }
Loading