Use http client factory for caldav and etesync

pull/1991/head
Alex Baker 2 years ago
parent 37a59099cf
commit 0ae473e27f

@ -1,33 +1,25 @@
package org.tasks.caldav
import android.content.Context
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.dav4jvm.BasicDigestAuthHandler
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Authenticator
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor
import org.tasks.R
import org.tasks.billing.Inventory
import org.tasks.data.CaldavAccount
import org.tasks.http.UserAgentInterceptor
import org.tasks.preferences.Preferences
import org.tasks.http.HttpClientFactory
import org.tasks.security.KeyStoreEncryption
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.net.ssl.SSLContext
class CaldavClientProvider @Inject constructor(
@ApplicationContext private val context: Context,
private val encryption: KeyStoreEncryption,
private val preferences: Preferences,
private val interceptor: DebugNetworkInterceptor,
private val inventory: Inventory
private val inventory: Inventory,
private val httpClientFactory: HttpClientFactory,
) {
private val tasksUrl = context.getString(R.string.tasks_caldav_url)
@ -37,11 +29,12 @@ class CaldavClientProvider @Inject constructor(
password: String? = null
): CaldavClient {
val auth = getAuthInterceptor(username, password, url)
val customCertManager = newCertManager()
customCertManager.appInForeground = true
return CaldavClient(
this,
createHttpClient(auth, customCertManager),
createHttpClient(
auth = auth,
foreground = true
),
url?.toHttpUrlOrNull()
)
}
@ -59,8 +52,7 @@ class CaldavClientProvider @Inject constructor(
account.getPassword(encryption),
account.url
)
val customCertManager = newCertManager()
val client = createHttpClient(auth, customCertManager)
val client = createHttpClient(auth)
return if (account.isTasksOrg) {
TasksClient(this, client, url?.toHttpUrlOrNull())
} else {
@ -68,10 +60,6 @@ class CaldavClientProvider @Inject constructor(
}
}
private suspend fun newCertManager() = withContext(Dispatchers.Default) {
CustomCertManager(context)
}
private fun getAuthInterceptor(
username: String?,
password: String?,
@ -82,31 +70,21 @@ class CaldavClientProvider @Inject constructor(
else -> BasicDigestAuthHandler(null, username, password)
}
private fun createHttpClient(auth: Interceptor?, customCertManager: CustomCertManager): OkHttpClient {
val hostnameVerifier = customCertManager.hostnameVerifier(OkHostnameVerifier)
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf(customCertManager), null)
val builder = OkHttpClient()
.newBuilder()
.cookieJar(MemoryCookieStore())
.followRedirects(false)
.followSslRedirects(true)
.sslSocketFactory(sslContext.socketFactory, customCertManager)
.hostnameVerifier(hostnameVerifier)
private suspend fun createHttpClient(
auth: Interceptor?,
foreground: Boolean = false,
): OkHttpClient {
return httpClientFactory.newClient(foreground = foreground) { builder ->
builder
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.addNetworkInterceptor(UserAgentInterceptor)
auth?.let {
builder.addNetworkInterceptor(it)
if (it is Authenticator) {
builder.authenticator(it)
}
auth?.let {
builder.addNetworkInterceptor(it)
if (it is Authenticator) {
builder.authenticator(it)
}
}
}
if (preferences.isFlipperEnabled) {
interceptor.apply(builder)
}
return builder.build()
}
}

@ -1,33 +1,26 @@
package org.tasks.etebase
import android.content.Context
import at.bitfire.cert4android.CustomCertManager
import com.etebase.client.Account
import com.etebase.client.Client
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor
import org.tasks.caldav.MemoryCookieStore
import org.tasks.data.CaldavAccount
import org.tasks.data.CaldavDao
import org.tasks.http.UserAgentInterceptor
import org.tasks.preferences.Preferences
import org.tasks.http.HttpClientFactory
import org.tasks.security.KeyStoreEncryption
import java.security.KeyManagementException
import java.security.NoSuchAlgorithmException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.net.ssl.SSLContext
class EtebaseClientProvider @Inject constructor(
@ApplicationContext private val context: Context,
private val encryption: KeyStoreEncryption,
private val preferences: Preferences,
private val interceptor: DebugNetworkInterceptor,
private val caldavDao: CaldavDao
private val caldavDao: CaldavDao,
private val httpClientFactory: HttpClientFactory,
) {
@Throws(NoSuchAlgorithmException::class, KeyManagementException::class)
suspend fun forAccount(account: CaldavAccount): EtebaseClient = forUrl(
@ -47,26 +40,11 @@ class EtebaseClientProvider @Inject constructor(
}
private suspend fun createHttpClient(foreground: Boolean): OkHttpClient {
val customCertManager = withContext(Dispatchers.Default) {
CustomCertManager(context, foreground)
}
val hostnameVerifier = customCertManager.hostnameVerifier(OkHostnameVerifier)
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf(customCertManager), null)
val builder = OkHttpClient()
.newBuilder()
.addNetworkInterceptor(UserAgentInterceptor)
.cookieJar(MemoryCookieStore())
.followRedirects(false)
.followSslRedirects(true)
.sslSocketFactory(sslContext.socketFactory, customCertManager)
.hostnameVerifier(hostnameVerifier)
return httpClientFactory.newClient(foreground = foreground) { builder ->
builder
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
if (preferences.isFlipperEnabled) {
interceptor.apply(builder)
}
return builder.build()
}
}

@ -6,6 +6,7 @@ import at.bitfire.dav4jvm.BasicDigestAuthHandler
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.CookieJar
import okhttp3.OkHttpClient
import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor
@ -19,45 +20,48 @@ class HttpClientFactory @Inject constructor(
private val preferences: Preferences,
private val interceptor: DebugNetworkInterceptor,
private val encryption: KeyStoreEncryption,
private val cookieJar: CookieJar,
) {
suspend fun newCertManager() = withContext(Dispatchers.Default) {
CustomCertManager(context)
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 ->
if (!username.isNullOrBlank() && !decrypted.isNullOrBlank()) {
val auth = BasicDigestAuthHandler(null, username, decrypted)
builder.addNetworkInterceptor(auth)
builder.authenticator(auth)
}
}
}
suspend fun newBuilder(
foreground: Boolean = false,
username: String? = null,
encryptedPassword: String? = null
): OkHttpClient.Builder = newBuilder(
newCertManager(),
foreground = foreground,
username = username,
password = encryptedPassword?.let { encryption.decrypt(it) }
)
fun newBuilder(
customCertManager: CustomCertManager,
foreground: Boolean = false,
username: String? = null,
password: String? = null
): OkHttpClient.Builder {
suspend fun newClient(
foreground: Boolean = false,
block: (OkHttpClient.Builder) -> Unit = {}
): OkHttpClient {
val customCertManager = withContext(Dispatchers.Default) {
CustomCertManager(context)
}
customCertManager.appInForeground = foreground
val hostnameVerifier = customCertManager.hostnameVerifier(OkHostnameVerifier)
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf(customCertManager), null)
val builder = OkHttpClient()
.newBuilder()
.sslSocketFactory(sslContext.socketFactory, customCertManager)
.hostnameVerifier(hostnameVerifier)
.newBuilder()
.followRedirects(false)
.followSslRedirects(true)
.sslSocketFactory(sslContext.socketFactory, customCertManager)
.hostnameVerifier(hostnameVerifier)
.addInterceptor(UserAgentInterceptor)
.cookieJar(cookieJar)
block(builder)
if (preferences.isFlipperEnabled) {
interceptor.apply(builder)
}
if (!username.isNullOrBlank() && !password.isNullOrBlank()) {
val auth = BasicDigestAuthHandler(null, username, password)
builder.addNetworkInterceptor(auth)
builder.authenticator(auth)
}
return builder
return builder.build()
}
}

@ -12,10 +12,12 @@ import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import okhttp3.CookieJar
import org.tasks.analytics.Firebase
import org.tasks.billing.BillingClient
import org.tasks.billing.BillingClientImpl
import org.tasks.billing.Inventory
import org.tasks.caldav.MemoryCookieStore
import org.tasks.data.*
import org.tasks.jobs.WorkManager
import org.tasks.notifications.NotificationDao
@ -121,4 +123,8 @@ class ApplicationModule {
@Provides
fun providesNotificationManager(@ApplicationContext context: Context) =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@Provides
@Singleton
fun cookieJar(): CookieJar = MemoryCookieStore()
}

@ -25,7 +25,7 @@ class GeocoderNominatim @Inject constructor(
override suspend fun reverseGeocode(mapPosition: MapPosition): Place? =
withContext(Dispatchers.IO) {
val client = httpClientFactory.newBuilder(foreground = true).build()
val client = httpClientFactory.newClient(foreground = true)
val url = "$url/reverse?format=geocodejson&lat=${mapPosition.latitude}&lon=${mapPosition.longitude}"
val response = client.newCall(
Request.Builder().get().url(url).addHeader(USER_AGENT, UA_VALUE).build()

@ -68,12 +68,11 @@ class PlaceSearchGoogle @Inject constructor(
context.getString(R.string.tasks_org_account_required)
)
val client = httpClientFactory
.newBuilder(
.newClient(
foreground = true,
username = account.username,
encryptedPassword = account.password
)
.build()
val response = client.newCall(Request.Builder().get().url(url).build()).execute()
if (response.isSuccessful) {
response.body?.string()?.toJson()?.apply { checkResult(this) }

Loading…
Cancel
Save