From 1d58292a07208eedd74b27245c01f1112e3a4d86 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sun, 7 May 2023 11:04:29 -0500 Subject: [PATCH] Separate cookie jars by username --- .../auth/MicrosoftAuthenticationActivity.kt | 2 +- .../BaseCaldavAccountSettingsActivity.kt | 4 ++-- .../org/tasks/caldav/CaldavClientProvider.kt | 9 ++++++++- .../java/org/tasks/caldav/TasksBasicAuth.kt | 2 +- .../org/tasks/etebase/EtebaseClientProvider.kt | 9 ++++++--- .../main/java/org/tasks/extensions/Context.kt | 10 ++++++++++ .../java/org/tasks/http/HttpClientFactory.kt | 18 ++++++++++++------ .../org/tasks/injection/ApplicationModule.kt | 6 ------ 8 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/tasks/auth/MicrosoftAuthenticationActivity.kt b/app/src/main/java/org/tasks/auth/MicrosoftAuthenticationActivity.kt index e294ffe76..5e40f5bbc 100644 --- a/app/src/main/java/org/tasks/auth/MicrosoftAuthenticationActivity.kt +++ b/app/src/main/java/org/tasks/auth/MicrosoftAuthenticationActivity.kt @@ -127,7 +127,7 @@ class MicrosoftAuthenticationActivity : ComponentActivity() { ) val userInfo = withContext(Dispatchers.IO) { httpClientFactory - .newClient() + .newClient(foreground = false) .newCall( Request.Builder() .url(discovery.userinfoEndpoint!!.toString()) diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt index 9e5d4e1c0..dff51be87 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt @@ -41,6 +41,7 @@ import org.tasks.data.CaldavDao import org.tasks.databinding.ActivityCaldavAccountSettingsBinding import org.tasks.dialogs.DialogBuilder import org.tasks.dialogs.Linkify +import org.tasks.extensions.Context.cookiePersistor import org.tasks.extensions.Context.openUri import org.tasks.injection.ThemedInjectingAppCompatActivity import org.tasks.security.KeyStoreEncryption @@ -59,7 +60,6 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv @Inject lateinit var taskDeleter: TaskDeleter @Inject lateinit var inventory: Inventory @Inject lateinit var firebase: Firebase - @Inject lateinit var cookiePersistor: CookiePersistor protected var caldavAccount: CaldavAccount? = null protected lateinit var binding: ActivityCaldavAccountSettingsBinding @@ -350,7 +350,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv } protected open suspend fun removeAccount() { - cookiePersistor.clearSession(caldavAccount?.url) + cookiePersistor(caldavAccount?.username).clearSession(caldavAccount?.url) taskDeleter.delete(caldavAccount!!) setResult(Activity.RESULT_OK) finish() diff --git a/app/src/main/java/org/tasks/caldav/CaldavClientProvider.kt b/app/src/main/java/org/tasks/caldav/CaldavClientProvider.kt index c5ba8cc30..8c6061bd4 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavClientProvider.kt +++ b/app/src/main/java/org/tasks/caldav/CaldavClientProvider.kt @@ -74,7 +74,14 @@ class CaldavClientProvider @Inject constructor( auth: Interceptor?, foreground: Boolean = false, ): 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 .connectTimeout(15, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) diff --git a/app/src/main/java/org/tasks/caldav/TasksBasicAuth.kt b/app/src/main/java/org/tasks/caldav/TasksBasicAuth.kt index 8e9b12340..95a4d9347 100644 --- a/app/src/main/java/org/tasks/caldav/TasksBasicAuth.kt +++ b/app/src/main/java/org/tasks/caldav/TasksBasicAuth.kt @@ -6,7 +6,7 @@ import okhttp3.Response import org.tasks.billing.Inventory class TasksBasicAuth( - user: String, + val user: String, token: String, private val inventory: Inventory ) : Interceptor { diff --git a/app/src/main/java/org/tasks/etebase/EtebaseClientProvider.kt b/app/src/main/java/org/tasks/etebase/EtebaseClientProvider.kt index 56c4aeabe..dc1f0d9a3 100644 --- a/app/src/main/java/org/tasks/etebase/EtebaseClientProvider.kt +++ b/app/src/main/java/org/tasks/etebase/EtebaseClientProvider.kt @@ -31,7 +31,7 @@ class EtebaseClientProvider @Inject constructor( @Throws(KeyManagementException::class, NoSuchAlgorithmException::class) 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 etebase = session ?.let { Account.restore(client, it, null) } @@ -39,8 +39,11 @@ class EtebaseClientProvider @Inject constructor( EtebaseClient(context, username, etebase, caldavDao) } - private suspend fun createHttpClient(foreground: Boolean): OkHttpClient { - return httpClientFactory.newClient(foreground = foreground) { builder -> + private suspend fun createHttpClient(foreground: Boolean, cookieKey: String): OkHttpClient { + return httpClientFactory.newClient( + foreground = foreground, + cookieKey = cookieKey, + ) { builder -> builder .connectTimeout(15, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) diff --git a/app/src/main/java/org/tasks/extensions/Context.kt b/app/src/main/java/org/tasks/extensions/Context.kt index f45cb50cf..9652c3f63 100644 --- a/app/src/main/java/org/tasks/extensions/Context.kt +++ b/app/src/main/java/org/tasks/extensions/Context.kt @@ -3,12 +3,14 @@ package org.tasks.extensions import android.content.ActivityNotFoundException import android.content.ContentResolver import android.content.Context +import android.content.Context.MODE_PRIVATE import android.content.Intent import android.content.Intent.ACTION_VIEW import android.net.Uri import android.widget.Toast import androidx.annotation.AnyRes import androidx.browser.customtabs.CustomTabsIntent +import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor import org.tasks.R object Context { @@ -55,4 +57,12 @@ object Context { .authority(packageName) .path(res.toString()) .build() + + fun Context.cookiePersistor(key: String? = null) = + SharedPrefsCookiePersistor( + getSharedPreferences( + "CookiePersistence${key?.let { "_$it" } ?: ""}", + MODE_PRIVATE + ) + ) } diff --git a/app/src/main/java/org/tasks/http/HttpClientFactory.kt b/app/src/main/java/org/tasks/http/HttpClientFactory.kt index af8b6e42a..0234ddd3a 100644 --- a/app/src/main/java/org/tasks/http/HttpClientFactory.kt +++ b/app/src/main/java/org/tasks/http/HttpClientFactory.kt @@ -3,7 +3,6 @@ package org.tasks.http import android.content.Context import at.bitfire.cert4android.CustomCertManager import at.bitfire.dav4jvm.BasicDigestAuthHandler -import com.franmontiel.persistentcookiejar.persistence.CookiePersistor import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -14,6 +13,7 @@ import okhttp3.internal.tls.OkHostnameVerifier import org.tasks.DebugNetworkInterceptor import org.tasks.caldav.TasksCookieJar import org.tasks.data.CaldavAccount +import org.tasks.extensions.Context.cookiePersistor import org.tasks.preferences.Preferences import org.tasks.security.KeyStoreEncryption import org.tasks.sync.microsoft.MicrosoftService @@ -28,15 +28,20 @@ class HttpClientFactory @Inject constructor( private val preferences: Preferences, private val interceptor: DebugNetworkInterceptor, private val encryption: KeyStoreEncryption, - private val cookiePersistor: CookiePersistor, ) { + suspend fun newClient(foreground: Boolean) = newClient( + foreground = foreground, + cookieKey = null, + block = {}, + ) + suspend fun newClient( foreground: Boolean = false, username: String? = null, encryptedPassword: String? = null ): OkHttpClient { val decrypted = encryptedPassword?.let { encryption.decrypt(it) } - return newClient(foreground = foreground) { builder -> + return newClient(foreground = foreground, cookieKey = username) { builder -> if (!username.isNullOrBlank() && !decrypted.isNullOrBlank()) { val auth = BasicDigestAuthHandler(null, username, decrypted) builder.addNetworkInterceptor(auth) @@ -47,6 +52,7 @@ class HttpClientFactory @Inject constructor( suspend fun newClient( foreground: Boolean = false, + cookieKey: String? = null, block: (OkHttpClient.Builder) -> Unit = {} ): OkHttpClient { val customCertManager = withContext(Dispatchers.Default) { @@ -63,7 +69,7 @@ class HttpClientFactory @Inject constructor( .sslSocketFactory(sslContext.socketFactory, customCertManager) .hostnameVerifier(hostnameVerifier) .addInterceptor(UserAgentInterceptor) - .cookieJar(TasksCookieJar(persistor = cookiePersistor)) + .cookieJar(TasksCookieJar(persistor = context.cookiePersistor(cookieKey))) block(builder) @@ -86,7 +92,7 @@ class HttpClientFactory @Inject constructor( if (!authState.isAuthorized) { throw RuntimeException("Needs authentication") } - val client = newClient { + val client = newClient(cookieKey = account.username) { it.addInterceptor { chain -> chain.proceed( chain.request().newBuilder() @@ -107,4 +113,4 @@ class HttpClientFactory @Inject constructor( const val URL_MICROSOFT = "https://graph.microsoft.com" val MEDIA_TYPE_JSON = "application/json".toMediaType() } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/tasks/injection/ApplicationModule.kt b/app/src/main/java/org/tasks/injection/ApplicationModule.kt index 11d650698..67f274c72 100644 --- a/app/src/main/java/org/tasks/injection/ApplicationModule.kt +++ b/app/src/main/java/org/tasks/injection/ApplicationModule.kt @@ -3,8 +3,6 @@ package org.tasks.injection import android.app.NotificationManager import android.content.Context import androidx.appcompat.app.AppCompatDelegate -import com.franmontiel.persistentcookiejar.persistence.CookiePersistor -import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor import com.todoroo.astrid.dao.Database import dagger.Module import dagger.Provides @@ -123,8 +121,4 @@ class ApplicationModule { @Provides fun providesNotificationManager(@ApplicationContext context: Context) = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - @Provides - fun cookiePersistor(@ApplicationContext context: Context): CookiePersistor = - SharedPrefsCookiePersistor(context) } \ No newline at end of file