Commit b2475d2b authored by Ricki Hirner's avatar Ricki Hirner 🐑

Refactoring

* refactor Settings and HttpClient
* library updates
parent d0341ef1
......@@ -32,6 +32,9 @@ android {
productFlavors {
standard {
versionName "1.9.2-ose"
buildConfigField "boolean", "customCerts", "true"
buildConfigField "boolean", "customCertsUI", "true"
}
}
......@@ -73,15 +76,15 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.android.support:appcompat-v7:27.0.0'
compile 'com.android.support:cardview-v7:27.0.0'
compile 'com.android.support:design:27.0.0'
compile 'com.android.support:preference-v14:27.0.0'
compile 'com.android.support:appcompat-v7:27.0.1'
compile 'com.android.support:cardview-v7:27.0.1'
compile 'com.android.support:design:27.0.1'
compile 'com.android.support:preference-v14:27.0.1'
compile 'com.github.yukuku:ambilwarna:2.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
compile 'commons-io:commons-io:2.5'
compile 'commons-io:commons-io:2.6'
compile 'dnsjava:dnsjava:2.1.8'
compile 'org.apache.commons:commons-lang3:3.6'
compile 'org.apache.commons:commons-collections4:4.1'
......
......@@ -36,7 +36,7 @@ public class SSLSocketFactoryCompatTest {
@Before
public void startServer() throws Exception {
certMgr = new CustomCertManager(getInstrumentation().getContext(), true, null);
certMgr = new CustomCertManager(getInstrumentation().getContext(), false, true);
factory = new SSLSocketFactoryCompat(certMgr);
server.start();
}
......
......@@ -8,7 +8,11 @@
package at.bitfire.davdroid;
import at.bitfire.davdroid.log.Logger
import okhttp3.HttpUrl
import org.xbill.DNS.Record
import org.xbill.DNS.SRVRecord
import org.xbill.DNS.TXTRecord
import java.util.*
object DavUtils {
......@@ -35,4 +39,27 @@ object DavUtils {
return "/"
}
fun selectSRVRecord(records: Array<Record>?): SRVRecord? {
val srvRecords = records?.filterIsInstance(SRVRecord::class.java)
srvRecords?.let {
if (it.size > 1)
Logger.log.warning("Multiple SRV records not supported yet; using first one")
return it.firstOrNull()
}
return null
}
fun pathsFromTXTRecords(records: Array<Record>?): List<String> {
val paths = LinkedList<String>()
records?.filterIsInstance(TXTRecord::class.java)?.forEach { txt ->
@Suppress("UNCHECKED_CAST")
for (segment in txt.strings as List<String>)
if (segment.startsWith("path=")) {
paths.add(segment.substring(5))
break
}
}
return paths
}
}
......@@ -15,6 +15,7 @@ import at.bitfire.cert4android.CustomCertManager
import at.bitfire.dav4android.BasicDigestAuthHandler
import at.bitfire.dav4android.UrlUtils
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.ISettings
import at.bitfire.davdroid.settings.Settings
import okhttp3.Cache
import okhttp3.Interceptor
......@@ -40,9 +41,9 @@ class HttpClient private constructor(
certManager?.close()
}
class Builder @JvmOverloads constructor(
val context: Context? = null,
val settings: ISettings? = null,
account: Account? = null,
accountSettings: AccountSettings? = null,
logger: java.util.logging.Logger = Logger.log
......@@ -74,29 +75,29 @@ class HttpClient private constructor(
orig.addInterceptor(loggingInterceptor)
}
context?.let {
Settings.getInstance(context)?.use { settings ->
// custom proxy support
try {
if (settings.getBoolean(App.OVERRIDE_PROXY, 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)
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)
settings?.let {
// custom proxy support
try {
if (settings.getBoolean(App.OVERRIDE_PROXY, 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)
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)
}
context?.let {
if (BuildConfig.customCerts)
customCertManager(CustomCertManager(context, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)))
customCertManager(CustomCertManager(context, BuildConfig.customCertsUI, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)))
// use account settings for authentication
val accountSettings = accountSettings ?: account?.let { AccountSettings(context, settings, it) }
val accountSettings = accountSettings ?: account?.let { AccountSettings(context, settings, account) }
accountSettings?.let {
val userName = accountSettings.username()
val password = accountSettings.password()
......
......@@ -35,22 +35,19 @@ object Logger {
val log = java.util.logging.Logger.getLogger("davdroid")!!
lateinit var context: Context
lateinit var preferences: SharedPreferences
fun initialize(context: Context) {
this.context = context
preferences = PreferenceManager.getDefaultSharedPreferences(context)
preferences.registerOnSharedPreferenceChangeListener { _, s ->
if (s == LOG_TO_EXTERNAL_STORAGE)
reinitialize()
reinitialize(context.applicationContext)
}
reinitialize()
reinitialize(context.applicationContext)
}
private fun reinitialize() {
private fun reinitialize(context: Context) {
val logToFile = preferences.getBoolean(LOG_TO_EXTERNAL_STORAGE, false)
val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG)
......
......@@ -96,10 +96,13 @@ class AppSettingsActivity: AppCompatActivity() {
}
// security settings
findPreference(App.DISTRUST_SYSTEM_CERTIFICATES).isVisible = BuildConfig.customCerts
val prefDistrustSystemCerts = findPreference(App.DISTRUST_SYSTEM_CERTIFICATES)
prefDistrustSystemCerts.isVisible = BuildConfig.customCerts
prefDistrustSystemCerts.isEnabled = BuildConfig.customCertsUI
val prefResetCertificates = findPreference("reset_certificates")
prefResetCertificates.isVisible = BuildConfig.customCerts
prefResetCertificates.isEnabled = BuildConfig.customCertsUI
prefResetCertificates.onPreferenceClickListener = Preference.OnPreferenceClickListener {
resetCertificates()
false
......@@ -181,7 +184,7 @@ class AppSettingsActivity: AppCompatActivity() {
}
private fun resetCertificates() {
if (CustomCertManager.resetCertificates(activity!!))
if (BuildConfig.customCertsUI && CustomCertManager.resetCertificates(activity!!))
Snackbar.make(view!!, getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show()
}
......
......@@ -25,6 +25,7 @@ import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.settings.Settings
import okhttp3.HttpUrl
import java.io.IOException
import java.io.StringWriter
......@@ -182,43 +183,43 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
Logger.log.log(Level.SEVERE, "Couldn't assemble Extended MKCOL request", e)
}
var httpClient: HttpClient? = null
try {
httpClient = HttpClient.Builder(context, account)
Settings.getInstance(context).use { settings ->
HttpClient.Builder(context, settings, account)
.setForeground(true)
.build()
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(info.url)!!)
// create collection on remote server
collection.mkCol(writer.toString())
// now insert collection into database:
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.writableDatabase
// 1. find service ID
val serviceType = when (info.type) {
CollectionInfo.Type.ADDRESS_BOOK -> ServiceDB.Services.SERVICE_CARDDAV
CollectionInfo.Type.CALENDAR -> ServiceDB.Services.SERVICE_CALDAV
else -> throw IllegalArgumentException("Collection must be an address book or calendar")
}
db.query(ServiceDB.Services._TABLE, arrayOf(ServiceDB.Services.ID),
"${ServiceDB.Services.ACCOUNT_NAME}=? AND ${ServiceDB.Services.SERVICE}=?",
arrayOf(account.name, serviceType), null, null, null).use { c ->
assert(c.moveToNext())
val serviceID = c.getLong(0)
// 2. add collection to service
val values = info.toDB()
values.put(ServiceDB.Collections.SERVICE_ID, serviceID)
db.insert(ServiceDB.Collections._TABLE, null, values)
.build().use { httpClient ->
try {
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(info.url)!!)
// create collection on remote server
collection.mkCol(writer.toString())
// now insert collection into database:
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.writableDatabase
// 1. find service ID
val serviceType = when (info.type) {
CollectionInfo.Type.ADDRESS_BOOK -> ServiceDB.Services.SERVICE_CARDDAV
CollectionInfo.Type.CALENDAR -> ServiceDB.Services.SERVICE_CALDAV
else -> throw IllegalArgumentException("Collection must be an address book or calendar")
}
db.query(ServiceDB.Services._TABLE, arrayOf(ServiceDB.Services.ID),
"${ServiceDB.Services.ACCOUNT_NAME}=? AND ${ServiceDB.Services.SERVICE}=?",
arrayOf(account.name, serviceType), null, null, null).use { c ->
assert(c.moveToNext())
val serviceID = c.getLong(0)
// 2. add collection to service
val values = info.toDB()
values.put(ServiceDB.Collections.SERVICE_ID, serviceID)
db.insert(ServiceDB.Collections._TABLE, null, values)
}
}
} catch(e: Exception) {
return e
}
}
} catch(e: Exception) {
return e
} finally {
httpClient?.close()
}
return null
}
......
......@@ -23,6 +23,7 @@ import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.settings.Settings
import okhttp3.HttpUrl
@Suppress("DEPRECATION")
......@@ -82,27 +83,27 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
override fun onStartLoading() = forceLoad()
override fun loadInBackground(): Exception? {
var httpClient: HttpClient? = null
try {
httpClient = HttpClient.Builder(context, account)
Settings.getInstance(context).use { settings ->
HttpClient.Builder(context, settings, account)
.setForeground(true)
.build()
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(collectionInfo.url)!!)
// delete collection from server
collection.delete(null)
// delete collection locally
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.writableDatabase
db.delete(ServiceDB.Collections._TABLE, "${ServiceDB.Collections.ID}=?", arrayOf(collectionInfo.id.toString()))
.build().use { httpClient ->
try {
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(collectionInfo.url)!!)
// delete collection from server
collection.delete(null)
// delete collection locally
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.writableDatabase
db.delete(ServiceDB.Collections._TABLE, "${ServiceDB.Collections.ID}=?", arrayOf(collectionInfo.id.toString()))
}
return null
} catch(e: Exception) {
return e
}
}
return null
} catch(e: Exception) {
return e
} finally {
httpClient?.close()
}
}
}
......
......@@ -13,13 +13,15 @@ import at.bitfire.dav4android.UrlUtils
import at.bitfire.dav4android.exception.DavException
import at.bitfire.dav4android.exception.HttpException
import at.bitfire.dav4android.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.log.StringHandler
import at.bitfire.davdroid.model.CollectionInfo
import okhttp3.HttpUrl
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
import org.apache.commons.lang3.builder.ToStringBuilder
import org.xbill.DNS.*
import org.xbill.DNS.Lookup
import org.xbill.DNS.Type
import java.io.Closeable
import java.io.IOException
import java.io.Serializable
......@@ -294,7 +296,7 @@ class DavResourceFinder(
val query = "_${service.wellKnownName}s._tcp.$domain"
log.fine("Looking up SRV records for $query")
val srv = selectSRVRecord(Lookup(query, Type.SRV).run())
val srv = DavUtils.selectSRVRecord(Lookup(query, Type.SRV).run())
if (srv != null) {
// choose SRV record to use (query may return multiple SRV records)
scheme = "https"
......@@ -310,15 +312,7 @@ class DavResourceFinder(
}
// look for TXT record too (for initial context path)
Lookup(query, Type.TXT).run()?.let {
for (record in it.filterIsInstance(TXTRecord::class.java))
for (segment in record.strings as List<String>)
if (segment.startsWith("path=")) {
paths.add(segment.substring(5))
log.info("Found TXT record; initial context path=$paths")
break
}
}
paths.addAll(DavUtils.pathsFromTXTRecords(Lookup(query, Type.TXT).run()))
// if there's TXT record and if it it's wrong, try well-known
paths.add("/.well-known/" + service.wellKnownName)
......@@ -374,19 +368,6 @@ class DavResourceFinder(
}
// helpers
private fun selectSRVRecord(records: Array<Record>?): SRVRecord? {
val srvRecords = records?.filterIsInstance(SRVRecord::class.java)
srvRecords?.let {
if (it.size > 1)
log.warning("Multiple SRV records not supported yet; using first one")
return it.firstOrNull()
}
return null
}
// data classes
class Configuration(
......
Subproject commit 38a5c2a06d92bf347d5c7e3d588d726db66c23c3
Subproject commit 0d1f40b43feae124e1b54bcdd78a227fed2f54e7
Subproject commit 1be2579cd0e8025c5753cdc4790a9eb64d7818ad
Subproject commit 7a92f25a293d4693f95091c10973eafd6acb010f
#!/bin/sh
adb shell setprop log.tag.cert4android VERBOSE
adb shell setprop log.tag.davdroid VERBOSE
adb shell setprop log.tag.dav4android VERBOSE
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment