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
This commit is contained in:
Hans-Christoph Steiner 2014-05-28 00:11:30 -04:00
parent 910f9a68a6
commit b619716669
5 changed files with 87 additions and 23 deletions

View File

@ -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

View File

@ -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";

View File

@ -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/.*");
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}
}