From b6197166694b303372a8c74a7a940e00fafd3ae2 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 28 May 2014 00:11:30 -0400 Subject: [PATCH] add TorHttpDownloader for handling repos on Tor Hidden Services Tor Hidden Services are on domain names that always end in .onion, so there is a URL pattern matcher that chooses which Downloader subclass to use based on testing for .onion. This is a quick, dumb implementation. It does make any attempt to see if Tor is running or even installed. That can come once NetCipher is easy to handle in the context of FDroid. refs #2367 https://dev.guardianproject.info/issues/2367 --- CHANGELOG.md | 2 + src/org/fdroid/fdroid/net/Downloader.java | 3 ++ .../fdroid/fdroid/net/DownloaderFactory.java | 16 ++++++- src/org/fdroid/fdroid/net/HttpDownloader.java | 44 +++++++++--------- .../fdroid/fdroid/net/TorHttpDownloader.java | 45 +++++++++++++++++++ 5 files changed, 87 insertions(+), 23 deletions(-) create mode 100644 src/org/fdroid/fdroid/net/TorHttpDownloader.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ea7c7e0d..3943d2260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ * find local repos on the same network using Bonjour/mDNS +* use FDroid repos on Tor Hidden Services (.onion addresses) + * directly send installed apps to other devices via Bluetooth and Android Beam (NFC+Bluetooth), also compatible with Samsung/HTC S-Beam diff --git a/src/org/fdroid/fdroid/net/Downloader.java b/src/org/fdroid/fdroid/net/Downloader.java index 4f6ee766d..4a9b96899 100644 --- a/src/org/fdroid/fdroid/net/Downloader.java +++ b/src/org/fdroid/fdroid/net/Downloader.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; +import java.net.URL; public abstract class Downloader { @@ -23,6 +24,8 @@ public abstract class Downloader { private ProgressListener progressListener = null; private Bundle eventData = null; private File outputFile; + + protected URL sourceUrl; protected String cacheTag = null; public static final String EVENT_PROGRESS = "downloadProgress"; diff --git a/src/org/fdroid/fdroid/net/DownloaderFactory.java b/src/org/fdroid/fdroid/net/DownloaderFactory.java index 8206db94b..df0ab415b 100644 --- a/src/org/fdroid/fdroid/net/DownloaderFactory.java +++ b/src/org/fdroid/fdroid/net/DownloaderFactory.java @@ -10,11 +10,23 @@ public class DownloaderFactory { public static Downloader create(String url, Context context) throws IOException { - return new HttpDownloader(url, context); + if (isOnionAddress(url)) { + return new TorHttpDownloader(url, context); + } else { + return new HttpDownloader(url, context); + } } public static Downloader create(String url, File destFile) throws IOException { - return new HttpDownloader(url, destFile); + if (isOnionAddress(url)) { + return new TorHttpDownloader(url, destFile); + } else { + return new HttpDownloader(url, destFile); + } + } + + private static boolean isOnionAddress(String url) { + return url.matches("^[a-zA-Z0-9]+://[^/]+\\.onion/.*"); } } diff --git a/src/org/fdroid/fdroid/net/HttpDownloader.java b/src/org/fdroid/fdroid/net/HttpDownloader.java index 7f5cc8e96..50fc41a65 100644 --- a/src/org/fdroid/fdroid/net/HttpDownloader.java +++ b/src/org/fdroid/fdroid/net/HttpDownloader.java @@ -16,11 +16,10 @@ import javax.net.ssl.SSLHandshakeException; public class HttpDownloader extends Downloader { private static final String TAG = "org.fdroid.fdroid.net.HttpDownloader"; - private static final String HEADER_IF_NONE_MATCH = "If-None-Match"; - private static final String HEADER_FIELD_ETAG = "ETag"; + protected static final String HEADER_IF_NONE_MATCH = "If-None-Match"; + protected static final String HEADER_FIELD_ETAG = "ETag"; - private URL sourceUrl; - private HttpURLConnection connection; + protected HttpURLConnection connection; private int statusCode = -1; // The context is required for opening the file to write to. @@ -54,28 +53,31 @@ public class HttpDownloader extends Downloader { @Override public void download() throws IOException, InterruptedException { try { - connection = (HttpURLConnection)sourceUrl.openConnection(); - - if (wantToCheckCache()) { - setupCacheCheck(); - Log.i(TAG, "Checking cached status of " + sourceUrl); - statusCode = connection.getResponseCode(); - } - - if (isCached()) { - Log.i(TAG, sourceUrl + " is cached, so not downloading (HTTP " + statusCode + ")"); - } else { - Log.i(TAG, "Downloading from " + sourceUrl); - downloadFromStream(); - updateCacheCheck(); - } + connection = (HttpURLConnection) sourceUrl.openConnection(); + doDownload(); } catch (SSLHandshakeException e) { - // TODO this should be handled better, it is not internationalised here. + // TODO this should be handled better, it is not internationalised here throw new IOException( "A problem occurred while establishing an SSL " + "connection. If this problem persists, AND you have a " + "very old device, you could try using http instead of " + - "https for the repo URL." + Log.getStackTraceString(e) ); + "https for the repo URL." + Log.getStackTraceString(e)); + } + } + + protected void doDownload() throws IOException, InterruptedException { + if (wantToCheckCache()) { + setupCacheCheck(); + Log.i(TAG, "Checking cached status of " + sourceUrl); + statusCode = connection.getResponseCode(); + } + + if (isCached()) { + Log.i(TAG, sourceUrl + " is cached, so not downloading (HTTP " + statusCode + ")"); + } else { + Log.i(TAG, "Downloading from " + sourceUrl); + downloadFromStream(); + updateCacheCheck(); } } diff --git a/src/org/fdroid/fdroid/net/TorHttpDownloader.java b/src/org/fdroid/fdroid/net/TorHttpDownloader.java new file mode 100644 index 000000000..13e6c09bb --- /dev/null +++ b/src/org/fdroid/fdroid/net/TorHttpDownloader.java @@ -0,0 +1,45 @@ + +package org.fdroid.fdroid.net; + +import android.content.Context; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.SocketAddress; + +import javax.net.ssl.SSLHandshakeException; + +public class TorHttpDownloader extends HttpDownloader { + + TorHttpDownloader(String url, Context ctx) throws IOException { + super(url, ctx); + } + + TorHttpDownloader(String url, File destFile) + throws FileNotFoundException, MalformedURLException { + super(url, destFile); + } + + @Override + public void download() throws IOException, InterruptedException { + try { + SocketAddress sa = new InetSocketAddress("127.0.0.1", 8118); + Proxy tor = new Proxy(Proxy.Type.HTTP, sa); + connection = (HttpURLConnection) sourceUrl.openConnection(tor); + doDownload(); + } catch (SSLHandshakeException e) { + throw new IOException( + "A problem occurred while establishing an SSL " + + "connection. If this problem persists, AND you have a " + + "very old device, you could try using http instead of " + + "https for the repo URL." + Log.getStackTraceString(e)); + } + } + +}