From af698c584b4dcf747e353b8fcbbcc5a86b0ebe1e Mon Sep 17 00:00:00 2001 From: rfc2822 Date: Fri, 22 Nov 2013 14:27:44 +0100 Subject: [PATCH] Bug fixes, SDK level 19 * use SDK level 19 * add action to all preference intents (fixes #92) * use StrictHostnameVerifier instead of HttpsURLConnection.getDefaultHostnameVerifier() (fixes #88) * use per-WebDavResource instead of static DavHttpClient to enable different settings for different accounts --- project.properties | 2 +- res/values-de/strings.xml | 7 +-- res/xml/account_prefs.xml | 3 +- src/at/bitfire/davdroid/URIUtils.java | 3 - .../davdroid/webdav/DavHttpClient.java | 55 ++++++++----------- .../davdroid/webdav/TlsSniSocketFactory.java | 7 ++- .../davdroid/webdav/WebDavResource.java | 16 ++++-- test/project.properties | 2 +- 8 files changed, 44 insertions(+), 51 deletions(-) diff --git a/project.properties b/project.properties index a3ee5ab6..4ab12569 100644 --- a/project.properties +++ b/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-19 diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 6da958e6..4b8f4207 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -42,8 +42,8 @@ installieren, um Datenverlust beim Neustart zu vermeiden (dies ist ein Android/Play Store-Bug).

Weitere Informationen erhalten Sie auf der DAVdroid-Homepage. - Dort finden Sie auch eine Anleitung zum Einrichten - DAVdroid ist auf den Schutz der Privatsphäre ausgelegt (siehe Datenschutzrichtlinie).

+ Dort finden Sie auch eine Anleitung zum Einrichten. + DAVdroid respektiert Ihre Privatsphäre (siehe Datenschutzrichtlinie).

Bei Problemen lesen Sie bitte die häufig gestellten Fragen. Im Falle eines Fehlers, der eindeutig durch DAVdroid verursacht wird, berichten Sie diesen wenn möglich auf @@ -57,8 +57,7 @@ über F-Droid bezogen werden.

Es ist jedoch viel Arbeit, die App zu entwickeln und besser zu machen. Daher haben wir uns entschlossen, sie - auch gegen eine kleine Gebühr in die Stores (Google Play, - Samsung Store) + auch gegen eine kleine Gebühr in die Stores (Google Play, Samsung Store) zu stellen. Wenn Sie das Projekt unterstützen wollen, können Sie für DAVdroid spenden oder die App kaufen.

diff --git a/res/xml/account_prefs.xml b/res/xml/account_prefs.xml index a86402ae..4613a696 100644 --- a/res/xml/account_prefs.xml +++ b/res/xml/account_prefs.xml @@ -4,7 +4,8 @@ + android:targetClass="at.bitfire.davdroid.MainActivity" + android:action="ACTION_VIEW" /> diff --git a/src/at/bitfire/davdroid/URIUtils.java b/src/at/bitfire/davdroid/URIUtils.java index 1fedd8da..6af7f61b 100644 --- a/src/at/bitfire/davdroid/URIUtils.java +++ b/src/at/bitfire/davdroid/URIUtils.java @@ -1,8 +1,5 @@ package at.bitfire.davdroid; -import java.net.URI; -import java.net.URISyntaxException; - import android.annotation.SuppressLint; import android.util.Log; diff --git a/src/at/bitfire/davdroid/webdav/DavHttpClient.java b/src/at/bitfire/davdroid/webdav/DavHttpClient.java index 617899ae..38ad3dad 100644 --- a/src/at/bitfire/davdroid/webdav/DavHttpClient.java +++ b/src/at/bitfire/davdroid/webdav/DavHttpClient.java @@ -1,57 +1,46 @@ package at.bitfire.davdroid.webdav; import org.apache.http.client.params.HttpClientParams; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import at.bitfire.davdroid.Constants; -import at.bitfire.davdroid.webdav.GzipDecompressingEntity; -import at.bitfire.davdroid.webdav.TlsSniSocketFactory; // see AndroidHttpClient public class DavHttpClient extends DefaultHttpClient { - private static DavHttpClient httpClient = null; - - private DavHttpClient(ClientConnectionManager connectionManager, HttpParams params) { - super(connectionManager, params); + private DavHttpClient(HttpParams params) { + super(params); } - public static synchronized DefaultHttpClient getInstance() { - if (httpClient == null) { - HttpParams params = new BasicHttpParams(); - params.setParameter(CoreProtocolPNames.USER_AGENT, "DAVdroid/" + Constants.APP_VERSION); - - // use defaults of AndroidHttpClient - HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); - HttpConnectionParams.setSoTimeout(params, 20 * 1000); - HttpConnectionParams.setSocketBufferSize(params, 8192); - HttpConnectionParams.setStaleCheckingEnabled(params, false); - - // don't allow redirections - HttpClientParams.setRedirecting(params, false); - - // use our own, SNI-capable LayeredSocketFactory for https:// - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), 443)); - - httpClient = new DavHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params); - - // allow gzip compression - GzipDecompressingEntity.enable(httpClient); - } + public static DefaultHttpClient getDefault() { + HttpParams params = new BasicHttpParams(); + params.setParameter(CoreProtocolPNames.USER_AGENT, "DAVdroid/" + Constants.APP_VERSION); + + // use defaults of AndroidHttpClient + HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); + HttpConnectionParams.setSoTimeout(params, 20 * 1000); + HttpConnectionParams.setSocketBufferSize(params, 8192); + HttpConnectionParams.setStaleCheckingEnabled(params, false); + + // don't allow redirections + HttpClientParams.setRedirecting(params, false); + + DavHttpClient httpClient = new DavHttpClient(params); + + // use our own, SNI-capable LayeredSocketFactory for https:// + SchemeRegistry schemeRegistry = httpClient.getConnectionManager().getSchemeRegistry(); + schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), 443)); + // allow gzip compression + GzipDecompressingEntity.enable(httpClient); return httpClient; } diff --git a/src/at/bitfire/davdroid/webdav/TlsSniSocketFactory.java b/src/at/bitfire/davdroid/webdav/TlsSniSocketFactory.java index 4a0a0eea..1f2103f1 100644 --- a/src/at/bitfire/davdroid/webdav/TlsSniSocketFactory.java +++ b/src/at/bitfire/davdroid/webdav/TlsSniSocketFactory.java @@ -5,13 +5,14 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLException; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import org.apache.http.conn.scheme.LayeredSocketFactory; +import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.apache.http.params.HttpParams; import android.annotation.TargetApi; @@ -27,6 +28,8 @@ public class TlsSniSocketFactory implements LayeredSocketFactory { // we will do this ourselves so we can set up SNI before SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getInsecure(0, null); + + final static HostnameVerifier hostnameVerifier = new StrictHostnameVerifier(); // Plain TCP/IP (layer below TLS) @@ -71,7 +74,7 @@ public class TlsSniSocketFactory implements LayeredSocketFactory { throw new SSLException("Cannot verify SSL socket without session"); // verify host name (important!) - if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(host, session)) + if (!hostnameVerifier.verify(host, session)) throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); return ssl; } diff --git a/src/at/bitfire/davdroid/webdav/WebDavResource.java b/src/at/bitfire/davdroid/webdav/WebDavResource.java index 63853e9f..00810d4a 100644 --- a/src/at/bitfire/davdroid/webdav/WebDavResource.java +++ b/src/at/bitfire/davdroid/webdav/WebDavResource.java @@ -86,7 +86,7 @@ public class WebDavResource { // content (available after GET) @Getter protected InputStream content; - protected DefaultHttpClient client = DavHttpClient.getInstance(); + protected DefaultHttpClient client; public WebDavResource(URI baseURL, boolean trailingSlash) throws URISyntaxException { @@ -99,22 +99,26 @@ public class WebDavResource { public WebDavResource(URI baseURL, String username, String password, boolean preemptive, boolean trailingSlash) throws URISyntaxException { this(baseURL, trailingSlash); + client = DavHttpClient.getDefault(); + // authenticate - client.getCredentialsProvider().setCredentials(new AuthScope(location.getHost(), location.getPort()), - new UsernamePasswordCredentials(username, password)); - // preemptive auth is available for Basic auth only + client.getCredentialsProvider().setCredentials( + new AuthScope(location.getHost(), location.getPort()), + new UsernamePasswordCredentials(username, password) + ); if (preemptive) { - Log.i(TAG, "Using preemptive Basic Authentication"); + Log.i(TAG, "Using preemptive authentication (not compatible with Digest auth)"); client.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0); } } protected WebDavResource(WebDavResource parent, URI uri) { location = uri; + client = parent.client; } public WebDavResource(WebDavResource parent, String member) { - location = parent.location.resolve(URIUtils.sanitize(member)); + this(parent, parent.location.resolve(URIUtils.sanitize(member))); } public WebDavResource(WebDavResource parent, String member, boolean trailingSlash) { diff --git a/test/project.properties b/test/project.properties index a3ee5ab6..4ab12569 100644 --- a/test/project.properties +++ b/test/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-19