Separate cookie jars by username

pull/2298/head
Alex Baker 3 years ago
parent df2a7f8857
commit 1d58292a07

@ -127,7 +127,7 @@ class MicrosoftAuthenticationActivity : ComponentActivity() {
) )
val userInfo = withContext(Dispatchers.IO) { val userInfo = withContext(Dispatchers.IO) {
httpClientFactory httpClientFactory
.newClient() .newClient(foreground = false)
.newCall( .newCall(
Request.Builder() Request.Builder()
.url(discovery.userinfoEndpoint!!.toString()) .url(discovery.userinfoEndpoint!!.toString())

@ -41,6 +41,7 @@ import org.tasks.data.CaldavDao
import org.tasks.databinding.ActivityCaldavAccountSettingsBinding import org.tasks.databinding.ActivityCaldavAccountSettingsBinding
import org.tasks.dialogs.DialogBuilder import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.Linkify import org.tasks.dialogs.Linkify
import org.tasks.extensions.Context.cookiePersistor
import org.tasks.extensions.Context.openUri import org.tasks.extensions.Context.openUri
import org.tasks.injection.ThemedInjectingAppCompatActivity import org.tasks.injection.ThemedInjectingAppCompatActivity
import org.tasks.security.KeyStoreEncryption import org.tasks.security.KeyStoreEncryption
@ -59,7 +60,6 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv
@Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var taskDeleter: TaskDeleter
@Inject lateinit var inventory: Inventory @Inject lateinit var inventory: Inventory
@Inject lateinit var firebase: Firebase @Inject lateinit var firebase: Firebase
@Inject lateinit var cookiePersistor: CookiePersistor
protected var caldavAccount: CaldavAccount? = null protected var caldavAccount: CaldavAccount? = null
protected lateinit var binding: ActivityCaldavAccountSettingsBinding protected lateinit var binding: ActivityCaldavAccountSettingsBinding
@ -350,7 +350,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv
} }
protected open suspend fun removeAccount() { protected open suspend fun removeAccount() {
cookiePersistor.clearSession(caldavAccount?.url) cookiePersistor(caldavAccount?.username).clearSession(caldavAccount?.url)
taskDeleter.delete(caldavAccount!!) taskDeleter.delete(caldavAccount!!)
setResult(Activity.RESULT_OK) setResult(Activity.RESULT_OK)
finish() finish()

@ -74,7 +74,14 @@ class CaldavClientProvider @Inject constructor(
auth: Interceptor?, auth: Interceptor?,
foreground: Boolean = false, foreground: Boolean = false,
): OkHttpClient { ): OkHttpClient {
return httpClientFactory.newClient(foreground = foreground) { builder -> return httpClientFactory.newClient(
foreground = foreground,
cookieKey = when (auth) {
is BasicDigestAuthHandler -> auth.username
is TasksBasicAuth -> auth.user
else -> null
}
) { builder ->
builder builder
.connectTimeout(15, TimeUnit.SECONDS) .connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS)

@ -6,7 +6,7 @@ import okhttp3.Response
import org.tasks.billing.Inventory import org.tasks.billing.Inventory
class TasksBasicAuth( class TasksBasicAuth(
user: String, val user: String,
token: String, token: String,
private val inventory: Inventory private val inventory: Inventory
) : Interceptor { ) : Interceptor {

@ -31,7 +31,7 @@ class EtebaseClientProvider @Inject constructor(
@Throws(KeyManagementException::class, NoSuchAlgorithmException::class) @Throws(KeyManagementException::class, NoSuchAlgorithmException::class)
suspend fun forUrl(url: String, username: String, password: String?, session: String? = null, foreground: Boolean = false): EtebaseClient = withContext(Dispatchers.IO) { suspend fun forUrl(url: String, username: String, password: String?, session: String? = null, foreground: Boolean = false): EtebaseClient = withContext(Dispatchers.IO) {
val httpClient = createHttpClient(foreground) val httpClient = createHttpClient(foreground, username)
val client = Client.create(httpClient, url) val client = Client.create(httpClient, url)
val etebase = session val etebase = session
?.let { Account.restore(client, it, null) } ?.let { Account.restore(client, it, null) }
@ -39,8 +39,11 @@ class EtebaseClientProvider @Inject constructor(
EtebaseClient(context, username, etebase, caldavDao) EtebaseClient(context, username, etebase, caldavDao)
} }
private suspend fun createHttpClient(foreground: Boolean): OkHttpClient { private suspend fun createHttpClient(foreground: Boolean, cookieKey: String): OkHttpClient {
return httpClientFactory.newClient(foreground = foreground) { builder -> return httpClientFactory.newClient(
foreground = foreground,
cookieKey = cookieKey,
) { builder ->
builder builder
.connectTimeout(15, TimeUnit.SECONDS) .connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS)

@ -3,12 +3,14 @@ package org.tasks.extensions
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.Intent import android.content.Intent
import android.content.Intent.ACTION_VIEW import android.content.Intent.ACTION_VIEW
import android.net.Uri import android.net.Uri
import android.widget.Toast import android.widget.Toast
import androidx.annotation.AnyRes import androidx.annotation.AnyRes
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor
import org.tasks.R import org.tasks.R
object Context { object Context {
@ -55,4 +57,12 @@ object Context {
.authority(packageName) .authority(packageName)
.path(res.toString()) .path(res.toString())
.build() .build()
fun Context.cookiePersistor(key: String? = null) =
SharedPrefsCookiePersistor(
getSharedPreferences(
"CookiePersistence${key?.let { "_$it" } ?: ""}",
MODE_PRIVATE
)
)
} }

@ -3,7 +3,6 @@ package org.tasks.http
import android.content.Context import android.content.Context
import at.bitfire.cert4android.CustomCertManager import at.bitfire.cert4android.CustomCertManager
import at.bitfire.dav4jvm.BasicDigestAuthHandler import at.bitfire.dav4jvm.BasicDigestAuthHandler
import com.franmontiel.persistentcookiejar.persistence.CookiePersistor
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -14,6 +13,7 @@ import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor import org.tasks.DebugNetworkInterceptor
import org.tasks.caldav.TasksCookieJar import org.tasks.caldav.TasksCookieJar
import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount
import org.tasks.extensions.Context.cookiePersistor
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.security.KeyStoreEncryption import org.tasks.security.KeyStoreEncryption
import org.tasks.sync.microsoft.MicrosoftService import org.tasks.sync.microsoft.MicrosoftService
@ -28,15 +28,20 @@ class HttpClientFactory @Inject constructor(
private val preferences: Preferences, private val preferences: Preferences,
private val interceptor: DebugNetworkInterceptor, private val interceptor: DebugNetworkInterceptor,
private val encryption: KeyStoreEncryption, private val encryption: KeyStoreEncryption,
private val cookiePersistor: CookiePersistor,
) { ) {
suspend fun newClient(foreground: Boolean) = newClient(
foreground = foreground,
cookieKey = null,
block = {},
)
suspend fun newClient( suspend fun newClient(
foreground: Boolean = false, foreground: Boolean = false,
username: String? = null, username: String? = null,
encryptedPassword: String? = null encryptedPassword: String? = null
): OkHttpClient { ): OkHttpClient {
val decrypted = encryptedPassword?.let { encryption.decrypt(it) } val decrypted = encryptedPassword?.let { encryption.decrypt(it) }
return newClient(foreground = foreground) { builder -> return newClient(foreground = foreground, cookieKey = username) { builder ->
if (!username.isNullOrBlank() && !decrypted.isNullOrBlank()) { if (!username.isNullOrBlank() && !decrypted.isNullOrBlank()) {
val auth = BasicDigestAuthHandler(null, username, decrypted) val auth = BasicDigestAuthHandler(null, username, decrypted)
builder.addNetworkInterceptor(auth) builder.addNetworkInterceptor(auth)
@ -47,6 +52,7 @@ class HttpClientFactory @Inject constructor(
suspend fun newClient( suspend fun newClient(
foreground: Boolean = false, foreground: Boolean = false,
cookieKey: String? = null,
block: (OkHttpClient.Builder) -> Unit = {} block: (OkHttpClient.Builder) -> Unit = {}
): OkHttpClient { ): OkHttpClient {
val customCertManager = withContext(Dispatchers.Default) { val customCertManager = withContext(Dispatchers.Default) {
@ -63,7 +69,7 @@ class HttpClientFactory @Inject constructor(
.sslSocketFactory(sslContext.socketFactory, customCertManager) .sslSocketFactory(sslContext.socketFactory, customCertManager)
.hostnameVerifier(hostnameVerifier) .hostnameVerifier(hostnameVerifier)
.addInterceptor(UserAgentInterceptor) .addInterceptor(UserAgentInterceptor)
.cookieJar(TasksCookieJar(persistor = cookiePersistor)) .cookieJar(TasksCookieJar(persistor = context.cookiePersistor(cookieKey)))
block(builder) block(builder)
@ -86,7 +92,7 @@ class HttpClientFactory @Inject constructor(
if (!authState.isAuthorized) { if (!authState.isAuthorized) {
throw RuntimeException("Needs authentication") throw RuntimeException("Needs authentication")
} }
val client = newClient { val client = newClient(cookieKey = account.username) {
it.addInterceptor { chain -> it.addInterceptor { chain ->
chain.proceed( chain.proceed(
chain.request().newBuilder() chain.request().newBuilder()

@ -3,8 +3,6 @@ package org.tasks.injection
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.franmontiel.persistentcookiejar.persistence.CookiePersistor
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor
import com.todoroo.astrid.dao.Database import com.todoroo.astrid.dao.Database
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -123,8 +121,4 @@ class ApplicationModule {
@Provides @Provides
fun providesNotificationManager(@ApplicationContext context: Context) = fun providesNotificationManager(@ApplicationContext context: Context) =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@Provides
fun cookiePersistor(@ApplicationContext context: Context): CookiePersistor =
SharedPrefsCookiePersistor(context)
} }
Loading…
Cancel
Save