mirror of
https://github.com/etesync/android
synced 2024-12-24 15:38:09 +00:00
Upgrade cert4android and refactor httpclient based on upstream
This commit is contained in:
parent
75020c1841
commit
4134f78da4
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the GNU Public License v3.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.etesync.syncadapter;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
|
|
||||||
import at.bitfire.cert4android.CustomCertManager;
|
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
|
||||||
|
|
||||||
import static androidx.test.InstrumentationRegistry.getTargetContext;
|
|
||||||
import static junit.framework.TestCase.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class SSLSocketFactoryCompatTest {
|
|
||||||
|
|
||||||
SSLSocketFactoryCompat factory;
|
|
||||||
MockWebServer server = new MockWebServer();
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void startServer() throws Exception {
|
|
||||||
factory = new SSLSocketFactoryCompat(new CustomCertManager(getTargetContext().getApplicationContext(), true));
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void stopServer() throws Exception {
|
|
||||||
server.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpgradeTLS() throws IOException {
|
|
||||||
Socket s = factory.createSocket(server.getHostName(), server.getPort());
|
|
||||||
assertTrue(s instanceof SSLSocket);
|
|
||||||
|
|
||||||
SSLSocket ssl = (SSLSocket)s;
|
|
||||||
assertFalse(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "SSLv3"));
|
|
||||||
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1"));
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 16) {
|
|
||||||
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1.1"));
|
|
||||||
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1.2"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -22,7 +22,6 @@ import android.os.StrictMode
|
|||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import at.bitfire.cert4android.CustomCertManager
|
|
||||||
import at.bitfire.ical4android.AndroidCalendar
|
import at.bitfire.ical4android.AndroidCalendar
|
||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
@ -38,18 +37,12 @@ import io.requery.Persistable
|
|||||||
import io.requery.android.sqlite.DatabaseSource
|
import io.requery.android.sqlite.DatabaseSource
|
||||||
import io.requery.meta.EntityModel
|
import io.requery.meta.EntityModel
|
||||||
import io.requery.sql.EntityDataStore
|
import io.requery.sql.EntityDataStore
|
||||||
import okhttp3.internal.tls.OkHostnameVerifier
|
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
import org.jetbrains.anko.doAsync
|
import org.jetbrains.anko.doAsync
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.net.ssl.HostnameVerifier
|
|
||||||
|
|
||||||
|
|
||||||
class App : Application() {
|
class App : Application() {
|
||||||
|
|
||||||
var certManager: CustomCertManager? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return [EntityDataStore] single instance for the application.
|
* @return [EntityDataStore] single instance for the application.
|
||||||
*
|
*
|
||||||
@ -70,7 +63,6 @@ class App : Application() {
|
|||||||
@SuppressLint("HardwareIds")
|
@SuppressLint("HardwareIds")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
reinitCertManager()
|
|
||||||
reinitLogger()
|
reinitLogger()
|
||||||
StrictMode.enableDefaults()
|
StrictMode.enableDefaults()
|
||||||
initPrefVersion()
|
initPrefVersion()
|
||||||
@ -120,22 +112,6 @@ class App : Application() {
|
|||||||
serviceDB.close()
|
serviceDB.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reinitCertManager() {
|
|
||||||
if (BuildConfig.customCerts) {
|
|
||||||
if (certManager != null)
|
|
||||||
certManager!!.close()
|
|
||||||
|
|
||||||
val dbHelper = ServiceDB.OpenHelper(this)
|
|
||||||
val settings = Settings(dbHelper.readableDatabase)
|
|
||||||
|
|
||||||
certManager = CustomCertManager(this, !settings.getBoolean(DISTRUST_SYSTEM_CERTIFICATES, false))
|
|
||||||
sslSocketFactoryCompat = SSLSocketFactoryCompat(certManager!!)
|
|
||||||
hostnameVerifier = certManager!!.hostnameVerifier(OkHostnameVerifier.INSTANCE)
|
|
||||||
|
|
||||||
dbHelper.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun reinitLogger() {
|
fun reinitLogger() {
|
||||||
Logger.initialize(this)
|
Logger.initialize(this)
|
||||||
}
|
}
|
||||||
@ -307,16 +283,6 @@ class App : Application() {
|
|||||||
|
|
||||||
var appName: String = "EteSync"
|
var appName: String = "EteSync"
|
||||||
|
|
||||||
var sslSocketFactoryCompat: SSLSocketFactoryCompat? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
var hostnameVerifier: HostnameVerifier? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
|
||||||
at.bitfire.cert4android.Constants.log = java.util.logging.Logger.getLogger("etesync.cert4android")
|
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var accountType: String
|
lateinit var accountType: String
|
||||||
private set
|
private set
|
||||||
lateinit var addressBookAccountType: String
|
lateinit var addressBookAccountType: String
|
||||||
|
@ -10,141 +10,227 @@ package com.etesync.syncadapter
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.security.KeyChain
|
||||||
|
import at.bitfire.cert4android.CertTlsSocketFactory
|
||||||
|
import at.bitfire.cert4android.CustomCertManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.ServiceDB
|
import com.etesync.syncadapter.model.ServiceDB
|
||||||
import com.etesync.syncadapter.model.Settings
|
import com.etesync.syncadapter.model.Settings
|
||||||
|
import okhttp3.Cache
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import okhttp3.internal.tls.OkHostnameVerifier
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
|
import java.net.Socket
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.text.SimpleDateFormat
|
import java.security.KeyStore
|
||||||
|
import java.security.Principal
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
import javax.net.ssl.KeyManager
|
||||||
|
import javax.net.ssl.TrustManagerFactory
|
||||||
|
import javax.net.ssl.X509ExtendedKeyManager
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
import java.util.logging.Logger as LoggerType
|
import java.util.logging.Logger as LoggerType
|
||||||
import com.etesync.syncadapter.log.Logger
|
|
||||||
|
|
||||||
object HttpClient {
|
class HttpClient private constructor(
|
||||||
private val client = OkHttpClient()
|
val okHttpClient: OkHttpClient,
|
||||||
private val userAgentInterceptor = UserAgentInterceptor()
|
private val certManager: CustomCertManager?
|
||||||
|
): AutoCloseable {
|
||||||
|
|
||||||
private val userAgent: String
|
companion object {
|
||||||
|
/** [OkHttpClient] singleton to build all clients from */
|
||||||
|
val sharedClient = OkHttpClient.Builder()
|
||||||
|
// set timeouts
|
||||||
|
.connectTimeout(15, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(120, TimeUnit.SECONDS)
|
||||||
|
|
||||||
init {
|
// don't allow redirects by default, because it would break PROPFIND handling
|
||||||
userAgent = "${App.appName}/${BuildConfig.VERSION_NAME} (okhttp3) Android/${Build.VERSION.RELEASE}"
|
.followRedirects(false)
|
||||||
|
|
||||||
|
// add User-Agent to every request
|
||||||
|
.addNetworkInterceptor(UserAgentInterceptor)
|
||||||
|
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create(context: Context?, logger: LoggerType, host: String?, token: String): OkHttpClient {
|
override fun close() {
|
||||||
var builder = defaultBuilder(context, logger)
|
certManager?.close()
|
||||||
|
|
||||||
// use account settings for authentication
|
|
||||||
builder = addAuthentication(builder, host, token)
|
|
||||||
|
|
||||||
return builder.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
class Builder(
|
||||||
fun create(context: Context?, settings: AccountSettings, logger: LoggerType = Logger.log): OkHttpClient {
|
val context: Context? = null,
|
||||||
return create(context, logger, settings.uri!!.host, settings.authToken)
|
accountSettings: AccountSettings? = null,
|
||||||
}
|
val logger: java.util.logging.Logger = Logger.log
|
||||||
|
) {
|
||||||
|
private var certManager: CustomCertManager? = null
|
||||||
|
private var certificateAlias: String? = null
|
||||||
|
|
||||||
@JvmOverloads
|
private val orig = sharedClient.newBuilder()
|
||||||
fun create(context: Context?, logger: LoggerType = Logger.log): OkHttpClient {
|
|
||||||
return defaultBuilder(context, logger).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun create(context: Context?, uri: URI, authToken: String): OkHttpClient {
|
init {
|
||||||
return create(context, Logger.log, uri.host, authToken)
|
// add network logging, if requested
|
||||||
}
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
|
||||||
|
message -> logger.finest(message)
|
||||||
|
})
|
||||||
|
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
orig.addInterceptor(loggingInterceptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
context?.let {
|
||||||
private fun defaultBuilder(context: Context?, logger: LoggerType): OkHttpClient.Builder {
|
val dbHelper = ServiceDB.OpenHelper(context)
|
||||||
val builder = client.newBuilder()
|
|
||||||
|
|
||||||
// use MemorizingTrustManager to manage self-signed certificates
|
|
||||||
if (context != null) {
|
|
||||||
val app = context.applicationContext as App
|
|
||||||
if (App.sslSocketFactoryCompat != null && app.certManager != null)
|
|
||||||
builder.sslSocketFactory(App.sslSocketFactoryCompat!!, app.certManager!!)
|
|
||||||
if (App.hostnameVerifier != null)
|
|
||||||
builder.hostnameVerifier(App.hostnameVerifier!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set timeouts
|
|
||||||
builder.connectTimeout(30, TimeUnit.SECONDS)
|
|
||||||
builder.writeTimeout(30, TimeUnit.SECONDS)
|
|
||||||
builder.readTimeout(120, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
// custom proxy support
|
|
||||||
if (context != null) {
|
|
||||||
val dbHelper = ServiceDB.OpenHelper(context)
|
|
||||||
try {
|
|
||||||
val settings = Settings(dbHelper.readableDatabase)
|
val settings = Settings(dbHelper.readableDatabase)
|
||||||
if (settings.getBoolean(App.OVERRIDE_PROXY, false)) {
|
val distrustSystemCerts = settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)
|
||||||
val address = InetSocketAddress(
|
|
||||||
settings.getString(App.OVERRIDE_PROXY_HOST, App.OVERRIDE_PROXY_HOST_DEFAULT),
|
|
||||||
settings.getInt(App.OVERRIDE_PROXY_PORT, App.OVERRIDE_PROXY_PORT_DEFAULT)
|
|
||||||
)
|
|
||||||
|
|
||||||
val proxy = Proxy(Proxy.Type.HTTP, address)
|
try {
|
||||||
builder.proxy(proxy)
|
if (settings.getBoolean(App.OVERRIDE_PROXY, false)) {
|
||||||
Logger.log.log(Level.INFO, "Using proxy", proxy)
|
val address = InetSocketAddress(
|
||||||
|
settings.getString(App.OVERRIDE_PROXY_HOST, App.OVERRIDE_PROXY_HOST_DEFAULT),
|
||||||
|
settings.getInt(App.OVERRIDE_PROXY_PORT, App.OVERRIDE_PROXY_PORT_DEFAULT)
|
||||||
|
)
|
||||||
|
|
||||||
|
val proxy = Proxy(Proxy.Type.HTTP, address)
|
||||||
|
orig.proxy(proxy)
|
||||||
|
Logger.log.log(Level.INFO, "Using proxy", proxy)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||||
|
} finally {
|
||||||
|
dbHelper.close()
|
||||||
}
|
}
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
//if (BuildConfig.customCerts)
|
||||||
} catch (e: NullPointerException) {
|
customCertManager(CustomCertManager(context, !distrustSystemCerts))
|
||||||
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
}
|
||||||
} finally {
|
|
||||||
dbHelper.close()
|
// use account settings for authentication
|
||||||
|
accountSettings?.let {
|
||||||
|
addAuthentication(accountSettings.uri!!.host, accountSettings.authToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add User-Agent to every request
|
constructor(context: Context, host: String?, authToken: String): this(context) {
|
||||||
builder.addNetworkInterceptor(userAgentInterceptor)
|
addAuthentication(host, authToken)
|
||||||
|
|
||||||
// add network logging, if requested
|
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
|
||||||
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { message -> logger.finest(message) })
|
|
||||||
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
|
||||||
builder.addInterceptor(loggingInterceptor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder
|
fun withDiskCache(): Builder {
|
||||||
}
|
val context = context ?: throw IllegalArgumentException("Context is required to find the cache directory")
|
||||||
|
for (dir in arrayOf(context.externalCacheDir, context.cacheDir).filterNotNull()) {
|
||||||
private fun addAuthentication(builder: OkHttpClient.Builder, host: String?, token: String): OkHttpClient.Builder {
|
if (dir.exists() && dir.canWrite()) {
|
||||||
val authHandler = TokenAuthenticator(host, token)
|
val cacheDir = File(dir, "HttpClient")
|
||||||
|
cacheDir.mkdir()
|
||||||
return builder.addNetworkInterceptor(authHandler)
|
Logger.log.fine("Using disk cache: $cacheDir")
|
||||||
}
|
orig.cache(Cache(cacheDir, 10*1024*1024))
|
||||||
|
break
|
||||||
private class TokenAuthenticator internal constructor(internal val host: String?, internal val token: String?) : Interceptor {
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
|
||||||
var request = chain.request()
|
|
||||||
|
|
||||||
/* Only add to the host we want. */
|
|
||||||
if (host == null || request.url().host() == host) {
|
|
||||||
if (token != null && request.header(HEADER_AUTHORIZATION) == null) {
|
|
||||||
request = request.newBuilder()
|
|
||||||
.header(HEADER_AUTHORIZATION, "Token $token")
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this
|
||||||
return chain.proceed(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
fun customCertManager(manager: CustomCertManager) {
|
||||||
protected val HEADER_AUTHORIZATION = "Authorization"
|
certManager = manager
|
||||||
}
|
}
|
||||||
|
fun setForeground(foreground: Boolean): Builder {
|
||||||
|
certManager?.appInForeground = foreground
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAuthentication(host: String?, token: String): Builder {
|
||||||
|
val authHandler = TokenAuthenticator(host, token)
|
||||||
|
|
||||||
|
orig.addNetworkInterceptor(authHandler)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TokenAuthenticator internal constructor(internal val host: String?, internal val token: String?) : Interceptor {
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
var request = chain.request()
|
||||||
|
|
||||||
|
/* Only add to the host we want. */
|
||||||
|
if (host == null || request.url().host() == host) {
|
||||||
|
if (token != null && request.header(HEADER_AUTHORIZATION) == null) {
|
||||||
|
request = request.newBuilder()
|
||||||
|
.header(HEADER_AUTHORIZATION, "Token $token")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
protected val HEADER_AUTHORIZATION = "Authorization"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): HttpClient {
|
||||||
|
val trustManager = certManager ?: {
|
||||||
|
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||||
|
factory.init(null as KeyStore?)
|
||||||
|
factory.trustManagers.first() as X509TrustManager
|
||||||
|
}()
|
||||||
|
|
||||||
|
val hostnameVerifier = certManager?.hostnameVerifier(OkHostnameVerifier.INSTANCE)
|
||||||
|
?: OkHostnameVerifier.INSTANCE
|
||||||
|
|
||||||
|
var keyManager: KeyManager? = null
|
||||||
|
try {
|
||||||
|
certificateAlias?.let { alias ->
|
||||||
|
val context = requireNotNull(context)
|
||||||
|
|
||||||
|
// get client certificate and private key
|
||||||
|
val certs = KeyChain.getCertificateChain(context, alias) ?: return@let
|
||||||
|
val key = KeyChain.getPrivateKey(context, alias) ?: return@let
|
||||||
|
logger.fine("Using client certificate $alias for authentication (chain length: ${certs.size})")
|
||||||
|
|
||||||
|
// create Android KeyStore (performs key operations without revealing secret data to DAVx5)
|
||||||
|
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
||||||
|
keyStore.load(null)
|
||||||
|
|
||||||
|
// create KeyManager
|
||||||
|
keyManager = object: X509ExtendedKeyManager() {
|
||||||
|
override fun getServerAliases(p0: String?, p1: Array<out Principal>?): Array<String>? = null
|
||||||
|
override fun chooseServerAlias(p0: String?, p1: Array<out Principal>?, p2: Socket?) = null
|
||||||
|
|
||||||
|
override fun getClientAliases(p0: String?, p1: Array<out Principal>?) =
|
||||||
|
arrayOf(alias)
|
||||||
|
|
||||||
|
override fun chooseClientAlias(p0: Array<out String>?, p1: Array<out Principal>?, p2: Socket?) =
|
||||||
|
alias
|
||||||
|
|
||||||
|
override fun getCertificateChain(forAlias: String?) =
|
||||||
|
certs.takeIf { forAlias == alias }
|
||||||
|
|
||||||
|
override fun getPrivateKey(forAlias: String?) =
|
||||||
|
key.takeIf { forAlias == alias }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.log(Level.SEVERE, "Couldn't set up client certificate authentication", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
orig.sslSocketFactory(CertTlsSocketFactory(keyManager, trustManager), trustManager)
|
||||||
|
orig.hostnameVerifier(hostnameVerifier)
|
||||||
|
|
||||||
|
return HttpClient(orig.build(), certManager)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class UserAgentInterceptor : Interceptor {
|
private object UserAgentInterceptor : Interceptor {
|
||||||
|
private val userAgent = "${App.appName}/${BuildConfig.VERSION_NAME} (okhttp3) Android/${Build.VERSION.RELEASE}"
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
val locale = Locale.getDefault()
|
val locale = Locale.getDefault()
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the GNU Public License v3.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.etesync.syncadapter
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import com.etesync.syncadapter.log.Logger
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.Socket
|
|
||||||
import java.security.GeneralSecurityException
|
|
||||||
import java.util.*
|
|
||||||
import javax.net.ssl.SSLContext
|
|
||||||
import javax.net.ssl.SSLSocket
|
|
||||||
import javax.net.ssl.SSLSocketFactory
|
|
||||||
import javax.net.ssl.X509TrustManager
|
|
||||||
|
|
||||||
class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory() {
|
|
||||||
|
|
||||||
private var delegate: SSLSocketFactory? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
try {
|
|
||||||
val sslContext = SSLContext.getInstance("TLS")
|
|
||||||
sslContext.init(null, arrayOf(trustManager), null)
|
|
||||||
delegate = sslContext.socketFactory
|
|
||||||
} catch (e: GeneralSecurityException) {
|
|
||||||
throw AssertionError() // The system has no TLS. Just give up.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun upgradeTLS(ssl: SSLSocket) {
|
|
||||||
if (protocols != null)
|
|
||||||
ssl.enabledProtocols = protocols
|
|
||||||
|
|
||||||
if (cipherSuites != null)
|
|
||||||
ssl.enabledCipherSuites = cipherSuites
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun getDefaultCipherSuites(): Array<String>? {
|
|
||||||
return cipherSuites
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSupportedCipherSuites(): Array<String>? {
|
|
||||||
return cipherSuites
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
|
|
||||||
val ssl = delegate!!.createSocket(s, host, port, autoClose)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(host: String, port: Int): Socket {
|
|
||||||
val ssl = delegate!!.createSocket(host, port)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
|
|
||||||
val ssl = delegate!!.createSocket(host, port, localHost, localPort)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(host: InetAddress, port: Int): Socket {
|
|
||||||
val ssl = delegate!!.createSocket(host, port)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
|
|
||||||
val ssl = delegate!!.createSocket(address, port, localAddress, localPort)
|
|
||||||
if (ssl is SSLSocket)
|
|
||||||
upgradeTLS(ssl)
|
|
||||||
return ssl
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// Android 5.0+ (API level 21) provides reasonable default settings
|
|
||||||
// but it still allows SSLv3
|
|
||||||
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
|
||||||
var protocols: Array<String>? = null
|
|
||||||
var cipherSuites: Array<String>? = null
|
|
||||||
init {
|
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
|
||||||
// Since Android 6.0 (API level 23),
|
|
||||||
// - TLSv1.1 and TLSv1.2 is enabled by default
|
|
||||||
// - SSLv3 is disabled by default
|
|
||||||
// - all modern ciphers are activated by default
|
|
||||||
protocols = null
|
|
||||||
cipherSuites = null
|
|
||||||
Logger.log.fine("Using device default TLS protocols/ciphers")
|
|
||||||
} else {
|
|
||||||
(SSLSocketFactory.getDefault().createSocket() as? SSLSocket)?.use { socket ->
|
|
||||||
try {
|
|
||||||
/* set reasonable protocol versions */
|
|
||||||
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
|
|
||||||
// - remove all SSL versions (especially SSLv3) because they're insecure now
|
|
||||||
val whichProtocols = LinkedList<String>()
|
|
||||||
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
|
|
||||||
whichProtocols += protocol
|
|
||||||
Logger.log.info("Enabling (only) these TLS protocols: ${whichProtocols.joinToString(", ")}")
|
|
||||||
protocols = whichProtocols.toTypedArray()
|
|
||||||
|
|
||||||
/* set up reasonable cipher suites */
|
|
||||||
val knownCiphers = arrayOf(
|
|
||||||
// TLS 1.2
|
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
// maximum interoperability
|
|
||||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
|
||||||
// additionally
|
|
||||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
|
||||||
)
|
|
||||||
val availableCiphers = socket.supportedCipherSuites
|
|
||||||
Logger.log.info("Available cipher suites: ${availableCiphers.joinToString(", ")}")
|
|
||||||
|
|
||||||
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
|
|
||||||
* disabling ciphers which are enabled by default, but have become unsecure), but for
|
|
||||||
* the security level of DAVx5 and maximum compatibility, disabling of insecure
|
|
||||||
* ciphers should be a server-side task */
|
|
||||||
|
|
||||||
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
|
|
||||||
val whichCiphers = LinkedList<String>()
|
|
||||||
whichCiphers.addAll(socket.enabledCipherSuites)
|
|
||||||
Logger.log.fine("Cipher suites enabled by default: ${whichCiphers.joinToString(", ")}")
|
|
||||||
// ... add explicitly allowed ciphers ...
|
|
||||||
whichCiphers.addAll(knownCiphers)
|
|
||||||
// ... and keep only those which are actually available
|
|
||||||
whichCiphers.retainAll(availableCiphers)
|
|
||||||
|
|
||||||
Logger.log.info("Enabling (only) these TLS ciphers: " + whichCiphers.joinToString(", "))
|
|
||||||
cipherSuites = whichCiphers.toTypedArray()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Logger.log.severe("Couldn't determine default TLS settings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -236,15 +236,7 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
var resourceClient = HttpClient.create(context)
|
val resourceClient = HttpClient.Builder(context).build().okHttpClient
|
||||||
|
|
||||||
// authenticate only against a certain host, and only upon request
|
|
||||||
// resourceClient = HttpClient.addAuthentication(resourceClient, baseUrl.host(), settings.username(), settings.password());
|
|
||||||
|
|
||||||
// allow redirects
|
|
||||||
resourceClient = resourceClient.newBuilder()
|
|
||||||
.followRedirects(true)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val response = resourceClient.newCall(Request.Builder()
|
val response = resourceClient.newCall(Request.Builder()
|
||||||
|
@ -111,7 +111,7 @@ abstract class SyncAdapterService : Service() {
|
|||||||
Logger.log.info("Refreshing " + serviceType + " collections of service #" + serviceType.toString())
|
Logger.log.info("Refreshing " + serviceType + " collections of service #" + serviceType.toString())
|
||||||
|
|
||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
val httpClient = HttpClient.create(context, settings)
|
val httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
|
|
||||||
val journalsManager = JournalManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
val journalsManager = JournalManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
init {
|
init {
|
||||||
|
|
||||||
// create HttpClient with given logger
|
// create HttpClient with given logger
|
||||||
httpClient = HttpClient.create(context, settings)
|
httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
|
|
||||||
data = (context.applicationContext as App).data
|
data = (context.applicationContext as App).data
|
||||||
val serviceEntity = JournalModel.Service.fetch(data, accountName, serviceType)
|
val serviceEntity = JournalModel.Service.fetch(data, accountName, serviceType)
|
||||||
|
@ -60,7 +60,7 @@ class AddMemberFragment : DialogFragment() {
|
|||||||
private inner class MemberAdd : AsyncTask<Void, Void, MemberAdd.AddResult>() {
|
private inner class MemberAdd : AsyncTask<Void, Void, MemberAdd.AddResult>() {
|
||||||
override fun doInBackground(vararg voids: Void): AddResult {
|
override fun doInBackground(vararg voids: Void): AddResult {
|
||||||
try {
|
try {
|
||||||
val httpClient = HttpClient.create(ctx!!, settings!!)
|
val httpClient = HttpClient.Builder(ctx, settings).build().okHttpClient
|
||||||
val userInfoManager = UserInfoManager(httpClient, remote!!)
|
val userInfoManager = UserInfoManager(httpClient, remote!!)
|
||||||
|
|
||||||
val userInfo = userInfoManager.fetch(memberEmail)
|
val userInfo = userInfoManager.fetch(memberEmail)
|
||||||
@ -102,7 +102,7 @@ class AddMemberFragment : DialogFragment() {
|
|||||||
override fun doInBackground(vararg voids: Void): AddResultSecond {
|
override fun doInBackground(vararg voids: Void): AddResultSecond {
|
||||||
try {
|
try {
|
||||||
val settings = settings!!
|
val settings = settings!!
|
||||||
val httpClient = HttpClient.create(ctx!!, settings)
|
val httpClient = HttpClient.Builder(ctx!!, settings).build().okHttpClient
|
||||||
val journalsManager = JournalManager(httpClient, remote!!)
|
val journalsManager = JournalManager(httpClient, remote!!)
|
||||||
|
|
||||||
val data = (ctx!!.applicationContext as App).data
|
val data = (ctx!!.applicationContext as App).data
|
||||||
|
@ -14,6 +14,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
|
import at.bitfire.cert4android.CustomCertManager
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
import com.etesync.syncadapter.BuildConfig
|
import com.etesync.syncadapter.BuildConfig
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
@ -43,7 +44,6 @@ class AppSettingsActivity : BaseActivity() {
|
|||||||
internal lateinit var settings: Settings
|
internal lateinit var settings: Settings
|
||||||
|
|
||||||
internal lateinit var prefResetHints: Preference
|
internal lateinit var prefResetHints: Preference
|
||||||
internal lateinit var prefResetCertificates: Preference
|
|
||||||
internal lateinit var prefOverrideProxy: SwitchPreferenceCompat
|
internal lateinit var prefOverrideProxy: SwitchPreferenceCompat
|
||||||
internal lateinit var prefDistrustSystemCerts: SwitchPreferenceCompat
|
internal lateinit var prefDistrustSystemCerts: SwitchPreferenceCompat
|
||||||
|
|
||||||
@ -125,7 +125,15 @@ class AppSettingsActivity : BaseActivity() {
|
|||||||
prefDistrustSystemCerts = findPreference("distrust_system_certs") as SwitchPreferenceCompat
|
prefDistrustSystemCerts = findPreference("distrust_system_certs") as SwitchPreferenceCompat
|
||||||
prefDistrustSystemCerts.isChecked = settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)
|
prefDistrustSystemCerts.isChecked = settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)
|
||||||
|
|
||||||
prefResetCertificates = findPreference("reset_certificates")
|
findPreference("reset_certificates").apply {
|
||||||
|
isVisible = BuildConfig.customCerts
|
||||||
|
isEnabled = true
|
||||||
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
resetCertificates()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val prefChangeNotification = findPreference("show_change_notification") as SwitchPreferenceCompat
|
val prefChangeNotification = findPreference("show_change_notification") as SwitchPreferenceCompat
|
||||||
prefChangeNotification.isChecked = context!!.defaultSharedPreferences.getBoolean(App.CHANGE_NOTIFICATION, true)
|
prefChangeNotification.isChecked = context!!.defaultSharedPreferences.getBoolean(App.CHANGE_NOTIFICATION, true)
|
||||||
@ -143,8 +151,6 @@ class AppSettingsActivity : BaseActivity() {
|
|||||||
resetHints()
|
resetHints()
|
||||||
else if (preference === prefDistrustSystemCerts)
|
else if (preference === prefDistrustSystemCerts)
|
||||||
setDistrustSystemCerts(preference.isChecked)
|
setDistrustSystemCerts(preference.isChecked)
|
||||||
else if (preference === prefResetCertificates)
|
|
||||||
resetCertificates()
|
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
@ -157,15 +163,11 @@ class AppSettingsActivity : BaseActivity() {
|
|||||||
|
|
||||||
private fun setDistrustSystemCerts(distrust: Boolean) {
|
private fun setDistrustSystemCerts(distrust: Boolean) {
|
||||||
settings.putBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, distrust)
|
settings.putBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, distrust)
|
||||||
|
|
||||||
// re-initialize certificate manager
|
|
||||||
val app = context!!.applicationContext as App
|
|
||||||
app.reinitCertManager()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetCertificates() {
|
private fun resetCertificates() {
|
||||||
(context!!.applicationContext as App).certManager?.resetCertificates()
|
if (CustomCertManager.resetCertificates(activity!!))
|
||||||
Snackbar.make(view!!, getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(view!!, getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class LanguageTask internal constructor(private val mListPreference: ListPreference) : AsyncTask<Void, Void, LanguageUtils.LocaleList>() {
|
private inner class LanguageTask internal constructor(private val mListPreference: ListPreference) : AsyncTask<Void, Void, LanguageUtils.LocaleList>() {
|
||||||
|
@ -15,22 +15,4 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
val app = applicationContext as App
|
|
||||||
val certManager = app.certManager
|
|
||||||
if (certManager != null)
|
|
||||||
certManager.appInForeground = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
|
|
||||||
val app = applicationContext as App
|
|
||||||
val certManager = app.certManager
|
|
||||||
if (certManager != null)
|
|
||||||
certManager.appInForeground = false
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -61,7 +61,7 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|||||||
|
|
||||||
fun changePasswordDo(old_password: String, new_password: String) {
|
fun changePasswordDo(old_password: String, new_password: String) {
|
||||||
val settings = AccountSettings(this, account)
|
val settings = AccountSettings(this, account)
|
||||||
val httpClient = HttpClient.create(this, settings)
|
val httpClient = HttpClient.Builder(this, settings).build().okHttpClient
|
||||||
|
|
||||||
doAsync {
|
doAsync {
|
||||||
Logger.log.info("Started deriving old key")
|
Logger.log.info("Started deriving old key")
|
||||||
|
@ -53,7 +53,7 @@ class CollectionMembersListFragment : ListFragment(), AdapterView.OnItemClickLis
|
|||||||
asyncTask = doAsync {
|
asyncTask = doAsync {
|
||||||
try {
|
try {
|
||||||
val settings = AccountSettings(context!!, account)
|
val settings = AccountSettings(context!!, account)
|
||||||
val httpClient = HttpClient.create(context!!, settings)
|
val httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
val journalsManager = JournalManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
val journalsManager = JournalManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
||||||
|
|
||||||
val journal = JournalManager.Journal.fakeWithUid(journalEntity.uid)
|
val journal = JournalManager.Journal.fakeWithUid(journalEntity.uid)
|
||||||
|
@ -101,7 +101,8 @@ class CreateCollectionFragment : DialogFragment(), LoaderManager.LoaderCallbacks
|
|||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
val principal = HttpUrl.get(settings.uri!!)
|
val principal = HttpUrl.get(settings.uri!!)
|
||||||
|
|
||||||
val journalManager = JournalManager(HttpClient.create(context, settings), principal!!)
|
val httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
|
val journalManager = JournalManager(httpClient, principal!!)
|
||||||
var uid = info.uid
|
var uid = info.uid
|
||||||
|
|
||||||
if (uid == null) {
|
if (uid == null) {
|
||||||
|
@ -88,7 +88,8 @@ class DeleteCollectionFragment : DialogFragment(), LoaderManager.LoaderCallbacks
|
|||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
val principal = HttpUrl.get(settings.uri!!)
|
val principal = HttpUrl.get(settings.uri!!)
|
||||||
|
|
||||||
val journalManager = JournalManager(HttpClient.create(context, settings), principal!!)
|
val httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
|
val journalManager = JournalManager(httpClient, principal!!)
|
||||||
val crypto = Crypto.CryptoManager(collectionInfo.version, settings.password(), collectionInfo.uid!!)
|
val crypto = Crypto.CryptoManager(collectionInfo.version, settings.password(), collectionInfo.uid!!)
|
||||||
|
|
||||||
journalManager.delete(JournalManager.Journal(crypto, collectionInfo.toJson(), collectionInfo.uid!!))
|
journalManager.delete(JournalManager.Journal(crypto, collectionInfo.toJson(), collectionInfo.uid!!))
|
||||||
|
@ -27,7 +27,7 @@ class RemoveMemberFragment : DialogFragment() {
|
|||||||
memberEmail = arguments!!.getString(KEY_MEMBER)
|
memberEmail = arguments!!.getString(KEY_MEMBER)
|
||||||
try {
|
try {
|
||||||
settings = AccountSettings(context!!, account!!)
|
settings = AccountSettings(context!!, account!!)
|
||||||
httpClient = HttpClient.create(context!!, settings!!)
|
httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import com.etesync.syncadapter.HttpClient
|
|||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.JournalAuthenticator
|
import com.etesync.syncadapter.journalmanager.JournalAuthenticator
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.log.StringHandler
|
import com.etesync.syncadapter.log.StringHandler
|
||||||
import com.etesync.syncadapter.model.CollectionInfo
|
import com.etesync.syncadapter.model.CollectionInfo
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
@ -20,22 +21,14 @@ import java.io.IOException
|
|||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.Level
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
class BaseConfigurationFinder(protected val context: Context, protected val credentials: LoginCredentials) {
|
class BaseConfigurationFinder(protected val context: Context, protected val credentials: LoginCredentials) {
|
||||||
|
|
||||||
protected val log: Logger
|
|
||||||
protected val logBuffer = StringHandler()
|
protected val logBuffer = StringHandler()
|
||||||
protected var httpClient: OkHttpClient
|
protected var httpClient: OkHttpClient
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
httpClient = HttpClient.Builder(context).build().okHttpClient
|
||||||
log = Logger.getLogger("syncadapter.BaseConfigurationFinder")
|
|
||||||
log.level = Level.FINEST
|
|
||||||
log.addHandler(logBuffer)
|
|
||||||
|
|
||||||
httpClient = HttpClient.create(context, log)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -50,11 +43,11 @@ class BaseConfigurationFinder(protected val context: Context, protected val cred
|
|||||||
try {
|
try {
|
||||||
authtoken = authenticator.getAuthToken(credentials.userName, credentials.password)
|
authtoken = authenticator.getAuthToken(credentials.userName, credentials.password)
|
||||||
} catch (e: Exceptions.HttpException) {
|
} catch (e: Exceptions.HttpException) {
|
||||||
log.warning(e.message)
|
Logger.log.warning(e.message)
|
||||||
|
|
||||||
failed = true
|
failed = true
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
log.warning(e.message)
|
Logger.log.warning(e.message)
|
||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +62,7 @@ class BaseConfigurationFinder(protected val context: Context, protected val cred
|
|||||||
protected fun findInitialConfiguration(service: CollectionInfo.Type): Configuration.ServiceInfo {
|
protected fun findInitialConfiguration(service: CollectionInfo.Type): Configuration.ServiceInfo {
|
||||||
// put discovered information here
|
// put discovered information here
|
||||||
val config = Configuration.ServiceInfo()
|
val config = Configuration.ServiceInfo()
|
||||||
log.info("Finding initial " + service.toString() + " service configuration")
|
Logger.log.info("Finding initial " + service.toString() + " service configuration")
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val cryptoManager: Crypto.CryptoManager
|
val cryptoManager: Crypto.CryptoManager
|
||||||
val httpClient = HttpClient.create(getContext(), config.url, config.authtoken!!)
|
val httpClient = HttpClient.Builder(context, config.url.host, config.authtoken!!).build().okHttpClient
|
||||||
|
|
||||||
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(config.url)!!)
|
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(config.url)!!)
|
||||||
val userInfo = userInfoManager.fetch(config.userName)
|
val userInfo = userInfoManager.fetch(config.userName)
|
||||||
|
@ -51,7 +51,7 @@ class SetupUserInfoFragment : DialogFragment() {
|
|||||||
override fun doInBackground(vararg accounts: Account): SetupUserInfo.SetupUserInfoResult {
|
override fun doInBackground(vararg accounts: Account): SetupUserInfo.SetupUserInfoResult {
|
||||||
try {
|
try {
|
||||||
val cryptoManager: Crypto.CryptoManager
|
val cryptoManager: Crypto.CryptoManager
|
||||||
val httpClient = HttpClient.create(context, settings)
|
val httpClient = HttpClient.Builder(context, settings).build().okHttpClient
|
||||||
|
|
||||||
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(settings.uri!!)!!)
|
||||||
var userInfo: UserInfoManager.UserInfo? = userInfoManager.fetch(account.name)
|
var userInfo: UserInfoManager.UserInfo? = userInfoManager.fetch(account.name)
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit af1ae810e8aceddd79fed17e6af8a88cb726bd55
|
Subproject commit f57a8ee9b11a74ca48c067b42dc0411259c567c8
|
Loading…
Reference in New Issue
Block a user