Browse Source

initial support for preference based proxy settings

and filtering to stop HTML5 media leakage
master
n8fr8 11 years ago
parent
commit
f70d889c03
  1. 28
      src/acr/browser/lightning/BrowserActivity.java
  2. 2
      src/acr/browser/lightning/IncognitoActivity.java
  3. 178
      src/acr/browser/lightning/LightningView.java
  4. 4
      src/acr/browser/lightning/PreferenceConstants.java
  5. 91
      src/acr/browser/lightning/ReplacingInputStream.java

28
src/acr/browser/lightning/BrowserActivity.java

@ -449,15 +449,20 @@ public class BrowserActivity extends Activity implements BrowserController {
getDir("icons", MODE_PRIVATE).getPath()); getDir("icons", MODE_PRIVATE).getPath());
} }
boolean useProxy = mPreferences.getBoolean(PreferenceConstants.USE_PROXY, false);
checkForTor ();
if (useProxy)
initializeTor();
else
checkForTor();
} }
/* /*
* If Orbot/Tor is installed, prompt the user if they want to enable proxying for this session * If Orbot/Tor is installed, prompt the user if they want to enable proxying for this session
*/ */
public void checkForTor () public boolean checkForTor ()
{ {
OrbotHelper oh = new OrbotHelper(this); OrbotHelper oh = new OrbotHelper(this);
@ -468,11 +473,16 @@ public class BrowserActivity extends Activity implements BrowserController {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
switch (which){ switch (which){
case DialogInterface.BUTTON_POSITIVE: case DialogInterface.BUTTON_POSITIVE:
mPreferences.edit().putBoolean(PreferenceConstants.USE_PROXY, true).apply();
initializeTor (); initializeTor ();
break; break;
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
mPreferences.edit().putBoolean(PreferenceConstants.USE_PROXY, false).apply();
break; break;
} }
} }
@ -481,7 +491,11 @@ public class BrowserActivity extends Activity implements BrowserController {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.use_tor_prompt).setPositiveButton(android.R.string.yes, dialogClickListener) builder.setMessage(R.string.use_tor_prompt).setPositiveButton(android.R.string.yes, dialogClickListener)
.setNegativeButton(android.R.string.no, dialogClickListener).show(); .setNegativeButton(android.R.string.no, dialogClickListener).show();
return true;
} }
return false;
} }
/* /*
@ -496,7 +510,9 @@ public class BrowserActivity extends Activity implements BrowserController {
WebkitProxy wkp = new WebkitProxy(); WebkitProxy wkp = new WebkitProxy();
try { try {
wkp.setProxy("acr.browser.lightning.BrowserApp", getApplicationContext(), "localhost",8118); String host = mPreferences.getString(PreferenceConstants.USE_PROXY_HOST, "localhost");
int port = mPreferences.getInt(PreferenceConstants.USE_PROXY_PORT, 8118);
wkp.setProxy("acr.browser.lightning.BrowserApp", getApplicationContext(), host, port);
} catch (Exception e) { } catch (Exception e) {
Log.d("Lightning","error enabling web proxying",e); Log.d("Lightning","error enabling web proxying",e);
} }
@ -1000,7 +1016,7 @@ public class BrowserActivity extends Activity implements BrowserController {
private synchronized void newTab(String url, boolean show) { private synchronized void newTab(String url, boolean show) {
mIsNewIntent = false; mIsNewIntent = false;
LightningView startingTab = new LightningView(mActivity, url); LightningView startingTab = new LightningView(mActivity, url, mCookieManager);
if (mIdGenerator == 0) { if (mIdGenerator == 0) {
startingTab.resumeTimers(); startingTab.resumeTimers();
} }

2
src/acr/browser/lightning/IncognitoActivity.java

@ -908,7 +908,7 @@ public class IncognitoActivity extends Activity implements BrowserController {
private synchronized void newTab(String url, boolean show) { private synchronized void newTab(String url, boolean show) {
mIsNewIntent = false; mIsNewIntent = false;
LightningView startingTab = new LightningView(mActivity, url); LightningView startingTab = new LightningView(mActivity, url, mCookieManager);
if (mIdGenerator == 0) { if (mIdGenerator == 0) {
startingTab.resumeTimers(); startingTab.resumeTimers();
} }

178
src/acr/browser/lightning/LightningView.java

@ -4,11 +4,19 @@
package acr.browser.lightning; package acr.browser.lightning;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import org.apache.http.util.ByteArrayBuffer;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
@ -28,10 +36,11 @@ import android.text.TextUtils;
import android.text.method.PasswordTransformationMethod; import android.text.method.PasswordTransformationMethod;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnTouchListener; import android.view.View.OnTouchListener;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions; import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler; import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler; import android.webkit.SslErrorHandler;
@ -44,7 +53,9 @@ import android.webkit.WebSettings.PluginState;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.VideoView;
public class LightningView { public class LightningView {
@ -62,9 +73,12 @@ public class LightningView {
private static SharedPreferences mPreferences; private static SharedPreferences mPreferences;
private static boolean mWideViewPort; private static boolean mWideViewPort;
private static AdBlock mAdBlock; private static AdBlock mAdBlock;
private CookieManager mCookieManager;
public LightningView(Activity activity, String url) {
@SuppressLint("NewApi")
public LightningView(Activity activity, String url, CookieManager cookieManager) {
mActivity = activity; mActivity = activity;
mCookieManager = cookieManager;
mWebView = new WebView(activity); mWebView = new WebView(activity);
mTitle = new Title(activity); mTitle = new Title(activity);
mAdBlock = new AdBlock(activity); mAdBlock = new AdBlock(activity);
@ -249,6 +263,7 @@ public class LightningView {
return Constants.FILE + homepage; return Constants.FILE + homepage;
} }
@SuppressLint("NewApi")
public synchronized void initializePreferences(Context context) { public synchronized void initializePreferences(Context context) {
mPreferences = context.getSharedPreferences( mPreferences = context.getSharedPreferences(
PreferenceConstants.PREFERENCES, 0); PreferenceConstants.PREFERENCES, 0);
@ -348,7 +363,7 @@ public class LightningView {
} }
} }
@SuppressLint("SetJavaScriptEnabled") @SuppressLint({ "SetJavaScriptEnabled", "NewApi" })
public void initializeSettings(WebSettings settings, Context context) { public void initializeSettings(WebSettings settings, Context context) {
if (API < 18) { if (API < 18) {
settings.setAppCacheMaxSize(Long.MAX_VALUE); settings.setAppCacheMaxSize(Long.MAX_VALUE);
@ -357,7 +372,7 @@ public class LightningView {
settings.setEnableSmoothTransition(true); settings.setEnableSmoothTransition(true);
} }
if (API > 16) { if (API > 16) {
settings.setMediaPlaybackRequiresUserGesture(true); settings.setMediaPlaybackRequiresUserGesture(true);
} }
if (API < 19) { if (API < 19) {
settings.setDatabasePath(context.getFilesDir().getAbsolutePath() settings.setDatabasePath(context.getFilesDir().getAbsolutePath()
@ -450,6 +465,7 @@ public class LightningView {
} }
} }
@SuppressLint("NewApi")
public synchronized void find(String text) { public synchronized void find(String text) {
if (mWebView != null) { if (mWebView != null) {
if (API > 16) { if (API > 16) {
@ -536,6 +552,7 @@ public class LightningView {
return ""; return "";
} }
public class LightningWebClient extends WebViewClient { public class LightningWebClient extends WebViewClient {
Context mActivity; Context mActivity;
@ -548,14 +565,121 @@ public class LightningView {
public WebResourceResponse shouldInterceptRequest(WebView view, public WebResourceResponse shouldInterceptRequest(WebView view,
String url) { String url) {
if (mAdBlock.isAd(url)) { if (mAdBlock.isAd(url)) {
Log.i("Blocked Domain:", url);
ByteArrayInputStream EMPTY = new ByteArrayInputStream( ByteArrayInputStream EMPTY = new ByteArrayInputStream(
"".getBytes()); "".getBytes());
WebResourceResponse response = new WebResourceResponse( WebResourceResponse response = new WebResourceResponse(
"text/plain", "utf-8", EMPTY); "text/plain", "utf-8", EMPTY);
return response; return response;
} }
return super.shouldInterceptRequest(view, url);
boolean useProxy = mPreferences.getBoolean(PreferenceConstants.USE_PROXY, false);
boolean mDoLeakHardening = false;
if (!useProxy)
return null;
if (!mDoLeakHardening)
return null;
//now we are going to proxy!
try
{
URL uURl = new URL(url);
Proxy proxy = null;
String host = mPreferences.getString(PreferenceConstants.USE_PROXY_HOST, "localhost");
int port = mPreferences.getInt(PreferenceConstants.USE_PROXY_PORT, 8118);
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
HttpURLConnection.setFollowRedirects(true);
HttpURLConnection conn = (HttpURLConnection)uURl.openConnection(proxy);
conn.setInstanceFollowRedirects(true);
conn.setRequestProperty("User-Agent", mSettings.getUserAgentString());
//conn.setRequestProperty("Transfer-Encoding", "chunked");
//conn.setUseCaches(false);
final int bufferSize = 1024 * 32;
conn.setChunkedStreamingMode(bufferSize);
String cType = conn.getContentType();
String cEnc = conn.getContentEncoding();
int connLen = conn.getContentLength();
if (cType != null)
{
String[] ctArray = cType.split(";");
cType = ctArray[0].trim();
if (cEnc == null && ctArray.length > 1)
{
cEnc = ctArray[1];
if (cEnc.indexOf('=')!=-1)
cEnc = cEnc.split("=")[1].trim();
}
}
if (connLen <= 0)
connLen = 2048;
if (cType != null && cType.startsWith("text"))
{
InputStream fStream = null;
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
ByteArrayBuffer baf = new ByteArrayBuffer(connLen);
int read = 0;
int bufSize = 2048;
byte[] buffer = new byte[bufSize];
while(true){
read = bis.read(buffer);
if(read==-1){
break;
}
baf.append(buffer, 0, read);
}
byte[] plainText = baf.toByteArray();
fStream = new ByteArrayInputStream(plainText);
fStream = new ReplacingInputStream(new ByteArrayInputStream(plainText),"poster=".getBytes(),"foo=".getBytes());
fStream = new ReplacingInputStream(fStream,"Poster=".getBytes(),"foo=".getBytes());
fStream = new ReplacingInputStream(fStream,"Poster=".getBytes(),"foo=".getBytes());
fStream = new ReplacingInputStream(fStream,".poster".getBytes(),".foo".getBytes());
fStream = new ReplacingInputStream(fStream,"\"poster\"".getBytes(),"\"foo\"".getBytes());
WebResourceResponse response = new WebResourceResponse(
cType, cEnc, fStream);
return response;
}/**
else if (mDoLeakHardening)
{
WebResourceResponse response = new WebResourceResponse(
cType, cEnc, conn.getInputStream());
return response;
}*/
else
{
return null; //let webkit handle it
}
}
catch (Exception e)
{
Log.e("Lightning","Error filtering stream",e);
ByteArrayInputStream EMPTY = new ByteArrayInputStream(
"".getBytes());
WebResourceResponse response = new WebResourceResponse(
"text/plain", "utf-8", EMPTY);
return response;
}
} }
@Override @Override
@ -871,9 +995,24 @@ public class LightningView {
@Override @Override
public void onShowCustomView(View view, CustomViewCallback callback) { public void onShowCustomView(View view, CustomViewCallback callback) {
Activity activity = mBrowserController.getActivity();
mBrowserController.onShowCustomView(view, if (view instanceof FrameLayout){
activity.getRequestedOrientation(), callback); FrameLayout frame = (FrameLayout) view;
if (frame.getFocusedChild() instanceof VideoView){
VideoView video = (VideoView) frame.getFocusedChild();
video.stopPlayback();
frame.removeView(video);
video.setVisibility(View.GONE);
}
}
else
{
Activity activity = mBrowserController.getActivity();
mBrowserController.onShowCustomView(view,
activity.getRequestedOrientation(), callback);
}
super.onShowCustomView(view, callback); super.onShowCustomView(view, callback);
} }
@ -881,8 +1020,23 @@ public class LightningView {
@Deprecated @Deprecated
public void onShowCustomView(View view, int requestedOrientation, public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) { CustomViewCallback callback) {
mBrowserController.onShowCustomView(view, requestedOrientation,
callback); if (view instanceof FrameLayout){
FrameLayout frame = (FrameLayout) view;
if (frame.getFocusedChild() instanceof VideoView){
VideoView video = (VideoView) frame.getFocusedChild();
video.stopPlayback();
frame.removeView(video);
video.setVisibility(View.GONE);
}
}
else
{
mBrowserController.onShowCustomView(view, requestedOrientation,
callback);
}
super.onShowCustomView(view, requestedOrientation, callback); super.onShowCustomView(view, requestedOrientation, callback);
} }

4
src/acr/browser/lightning/PreferenceConstants.java

@ -31,4 +31,8 @@ public class PreferenceConstants {
public static final String USER_AGENT = "agentchoose"; public static final String USER_AGENT = "agentchoose";
public static final String USER_AGENT_STRING = "userAgentString"; public static final String USER_AGENT_STRING = "userAgentString";
public static final String GOOGLE_SEARCH_SUGGESTIONS = "GoogleSearchSuggestions"; public static final String GOOGLE_SEARCH_SUGGESTIONS = "GoogleSearchSuggestions";
public static final String USE_PROXY = "useProxy";
public static final String USE_PROXY_HOST = "useProxyHost";
public static final String USE_PROXY_PORT = "useProxyPort";
} }

91
src/acr/browser/lightning/ReplacingInputStream.java

@ -0,0 +1,91 @@
package acr.browser.lightning;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedList;
public class ReplacingInputStream extends FilterInputStream {
LinkedList<Integer> inQueue = new LinkedList<Integer>();
LinkedList<Integer> outQueue = new LinkedList<Integer>();
final byte[] search, replacement;
protected ReplacingInputStream(InputStream in, byte[] search,
byte[] replacement) {
super(in);
this.search = search;
this.replacement = replacement;
}
private boolean isMatchFound() {
Iterator<Integer> inIter = inQueue.iterator();
for (int i = 0; i < search.length; i++)
if (!inIter.hasNext() || search[i] != inIter.next())
return false;
return true;
}
private void readAhead() throws IOException {
// Work up some look-ahead.
while (inQueue.size() < search.length) {
int next = super.read();
inQueue.offer(next);
if (next == -1)
break;
}
}
@Override
public int read() throws IOException {
// Next byte already determined.
if (outQueue.isEmpty()) {
readAhead();
if (isMatchFound()) {
for (int i = 0; i < search.length; i++)
inQueue.remove();
for (byte b : replacement)
outQueue.offer((int) b);
} else
outQueue.add(inQueue.remove());
}
return outQueue.remove();
}
/**
* Returns false. REFilterInputStream does not support mark() and
* reset() methods.
*/
public boolean markSupported() {
return false;
}
/** Reads from the stream into the provided array.
* @throws IOException */
public int read(byte[] b, int off, int len) throws IOException {
int i;
int ok = 0;
while (len-- > 0) {
i = read();
if (i == -1) return (ok == 0) ? -1 : ok;
b[off++] = (byte) i;
ok++;
}
return ok;
}
@Override
public int read(byte[] buffer) throws IOException {
return read(buffer, 0, buffer.length);
}
}
Loading…
Cancel
Save