mirror of https://github.com/tasks/tasks
Add CaldavClientProvider with support for tokens
parent
50c62a4114
commit
75d130556c
@ -0,0 +1,16 @@
|
|||||||
|
package org.tasks.auth
|
||||||
|
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
|
|
||||||
|
class GoogleSignInAccount(
|
||||||
|
private val account: GoogleSignInAccount
|
||||||
|
) : OauthSignIn {
|
||||||
|
override val id: String?
|
||||||
|
get() = account.id
|
||||||
|
|
||||||
|
override val idToken: String?
|
||||||
|
get() = account.idToken
|
||||||
|
|
||||||
|
override val email: String?
|
||||||
|
get() = account.email
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package org.tasks.auth
|
||||||
|
|
||||||
|
interface OauthSignIn {
|
||||||
|
val idToken: String?
|
||||||
|
val email: String?
|
||||||
|
val id: String?
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
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.billing.Inventory
|
||||||
|
import org.tasks.data.CaldavAccount
|
||||||
|
import org.tasks.gtasks.PlayServices
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
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 playServices: PlayServices,
|
||||||
|
private val inventory: Inventory
|
||||||
|
) {
|
||||||
|
suspend fun forUrl(
|
||||||
|
url: String?,
|
||||||
|
username: String? = null,
|
||||||
|
password: String? = null,
|
||||||
|
token: String? = null): CaldavClient {
|
||||||
|
val auth = getAuthInterceptor(username = username, password = password, token = token)
|
||||||
|
val customCertManager = newCertManager()
|
||||||
|
return CaldavClient(
|
||||||
|
this,
|
||||||
|
customCertManager,
|
||||||
|
createHttpClient(auth, customCertManager),
|
||||||
|
url?.toHttpUrlOrNull()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun forAccount(account: CaldavAccount, url: String? = account.url): CaldavClient {
|
||||||
|
val auth = getAuthInterceptor(account)
|
||||||
|
val customCertManager = newCertManager()
|
||||||
|
return CaldavClient(
|
||||||
|
this,
|
||||||
|
customCertManager,
|
||||||
|
createHttpClient(auth, customCertManager),
|
||||||
|
url?.toHttpUrlOrNull()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun newCertManager() = withContext(Dispatchers.Default) {
|
||||||
|
CustomCertManager(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getAuthInterceptor(
|
||||||
|
account: CaldavAccount? = null,
|
||||||
|
username: String? = account?.username,
|
||||||
|
password: String? = account?.getPassword(encryption),
|
||||||
|
token: String? = null
|
||||||
|
): Interceptor? {
|
||||||
|
return when {
|
||||||
|
account?.isTasksOrg == true -> playServices.getSignedInAccount()?.let {
|
||||||
|
TokenInterceptor(it.idToken!!, inventory)
|
||||||
|
}
|
||||||
|
username?.isNotBlank() == true && password?.isNotBlank() == true ->
|
||||||
|
BasicDigestAuthHandler(null, username, password)
|
||||||
|
token?.isNotBlank() == true ->
|
||||||
|
TokenInterceptor(token, inventory)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createHttpClient(auth: Interceptor?, customCertManager: CustomCertManager, foreground: Boolean = false): OkHttpClient {
|
||||||
|
customCertManager.appInForeground = foreground
|
||||||
|
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)
|
||||||
|
.connectTimeout(15, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(120, TimeUnit.SECONDS)
|
||||||
|
auth?.let {
|
||||||
|
builder.addNetworkInterceptor(it)
|
||||||
|
if (it is Authenticator) {
|
||||||
|
builder.authenticator(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (preferences.isFlipperEnabled) {
|
||||||
|
interceptor.apply(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package org.tasks.caldav
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.tasks.billing.Inventory
|
||||||
|
|
||||||
|
class TokenInterceptor(
|
||||||
|
private val token: String,
|
||||||
|
private val inventory: Inventory
|
||||||
|
) : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val builder = chain.request().newBuilder().header(AUTHORIZATION, "Bearer $token")
|
||||||
|
inventory.subscription?.let {
|
||||||
|
builder.header(SKU, it.sku)
|
||||||
|
builder.header(TOKEN, it.purchaseToken)
|
||||||
|
}
|
||||||
|
return chain.proceed(builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val AUTHORIZATION = "Authorization"
|
||||||
|
private const val SKU = "tasks-sku"
|
||||||
|
private const val TOKEN = "tasks-token"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue