diff --git a/res/raw/js_removewords b/res/raw/js_removewords new file mode 100644 index 0000000..c44b27a --- /dev/null +++ b/res/raw/js_removewords @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/res/values/spoofs.xml b/res/values/spoofs.xml index 2601827..869f06b 100644 --- a/res/values/spoofs.xml +++ b/res/values/spoofs.xml @@ -49,4 +49,13 @@ Reverse title Reverse all website titles + Flip content + Turn the content of all websites upside down + Websites experience gravity + All elements on websites fall to the bottom of the page + Delete random words + Words disappear from pages every second + + Change text + Replace words with others diff --git a/src/uk/digitalsquid/netspoofer/config/IOHelpers.java b/src/uk/digitalsquid/netspoofer/config/IOHelpers.java index 20fd933..0c34a84 100644 --- a/src/uk/digitalsquid/netspoofer/config/IOHelpers.java +++ b/src/uk/digitalsquid/netspoofer/config/IOHelpers.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; @@ -40,12 +41,14 @@ private IOHelpers() {} * @throws IOException */ public static final String readFileContents(InputStream is) throws IOException { - StringBuffer out = new StringBuffer(); - byte[] b = new byte[256]; - for (int n; (n = is.read(b)) != -1;) { - out.append(new String(b, 0, n)); + StringWriter out = new StringWriter(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + String line; + while((line = reader.readLine()) != null) { + out.append(line); + out.append('\n'); } - is.close(); + reader.close(); return out.toString(); } diff --git a/src/uk/digitalsquid/netspoofer/config/Lists.java b/src/uk/digitalsquid/netspoofer/config/Lists.java index 38fe435..8d42e38 100644 --- a/src/uk/digitalsquid/netspoofer/config/Lists.java +++ b/src/uk/digitalsquid/netspoofer/config/Lists.java @@ -22,6 +22,7 @@ package uk.digitalsquid.netspoofer.config; import java.util.ArrayList; +import java.util.Map; public final class Lists { private Lists() {} @@ -31,4 +32,14 @@ public static final ArrayList singleton(T x) { result.add(x); return result; } + + public static final String map(Map map, String in) { + StringBuilder result = new StringBuilder(in.length()); + for(char c : in.toCharArray()) { + Character ud = map.get(c); + if(ud == null) ud = c; + result.append(ud); + } + return result.toString(); + } } diff --git a/src/uk/digitalsquid/netspoofer/config/RunManager.java b/src/uk/digitalsquid/netspoofer/config/RunManager.java index 75736f7..55ab41e 100644 --- a/src/uk/digitalsquid/netspoofer/config/RunManager.java +++ b/src/uk/digitalsquid/netspoofer/config/RunManager.java @@ -31,7 +31,9 @@ import java.util.Map; import uk.digitalsquid.netspoofer.proxy.NSProxy; +import uk.digitalsquid.netspoofer.spoofs.ContentChange; import uk.digitalsquid.netspoofer.spoofs.CustomGalleryImageChange; +import uk.digitalsquid.netspoofer.spoofs.CustomTextChange; import uk.digitalsquid.netspoofer.spoofs.ImageSpoof; import uk.digitalsquid.netspoofer.spoofs.MultiSpoof; import uk.digitalsquid.netspoofer.spoofs.NullSpoof; @@ -69,11 +71,17 @@ public ArrayList getSpoofList() { spoofs.add(new VideoChange(context, true)); spoofs.add(new VideoChange(context, false)); + spoofs.add(new CustomTextChange(context)); + spoofs.add(new RedirectSpoof(context, RedirectSpoof.MODE_BLUEBALL)); spoofs.add(new RedirectSpoof(context, RedirectSpoof.MODE_CUSTOM)); spoofs.add(new TitleChange(context, TitleChange.MODE_FLIP)); spoofs.add(new TitleChange(context, TitleChange.MODE_REVERSE)); + + spoofs.add(new ContentChange(context, ContentChange.MODE_FLIP)); + spoofs.add(new ContentChange(context, ContentChange.MODE_GRAVITY)); + spoofs.add(new ContentChange(context, ContentChange.MODE_DELETE)); Collections.sort(spoofs); diff --git a/src/uk/digitalsquid/netspoofer/proxy/NSProxy.java b/src/uk/digitalsquid/netspoofer/proxy/NSProxy.java index 117b8ca..366199e 100644 --- a/src/uk/digitalsquid/netspoofer/proxy/NSProxy.java +++ b/src/uk/digitalsquid/netspoofer/proxy/NSProxy.java @@ -166,7 +166,8 @@ protected int doInBackground(StartParams params) { Log.d(TAG, "Sending request"); HttpResponse response = executeRequest(request); Log.d(TAG, "Response received"); - manipulateResponse(response, request); + if(!whitelistRequest(request)) + manipulateResponse(response, request); Log.d(TAG, "Response manipulated"); output.write(String.format("HTTP/1.1 %d %s\r\n", response.getResponseCode(), @@ -278,4 +279,15 @@ private boolean filterRequest(HttpRequest request) { if(host.contains(".dropbox.com")) return false; return true; } + + /** + * Filters out requests that shouldn't be modified. + * @param request + * @return true if the request shouldn't be modified. + */ + private boolean whitelistRequest(HttpRequest request) { + String host = request.getHost(); + if(host.equals("gravityscript.googlecode.com")) return true; + return false; + } } diff --git a/src/uk/digitalsquid/netspoofer/spoofs/ContentChange.java b/src/uk/digitalsquid/netspoofer/spoofs/ContentChange.java new file mode 100644 index 0000000..1e72b6b --- /dev/null +++ b/src/uk/digitalsquid/netspoofer/spoofs/ContentChange.java @@ -0,0 +1,127 @@ +package uk.digitalsquid.netspoofer.spoofs; + +import java.io.IOException; + +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; + +import uk.digitalsquid.netspoofer.R; +import uk.digitalsquid.netspoofer.config.IOHelpers; +import uk.digitalsquid.netspoofer.config.Lists; +import uk.digitalsquid.netspoofer.config.LogConf; +import android.content.Context; +import android.content.res.Resources.NotFoundException; +import android.util.Log; + +public class ContentChange extends HtmlEditorSpoof implements LogConf { + + private static final long serialVersionUID = 792590861534877480L; + public static final int MODE_FLIP = 1; + public static final int MODE_GRAVITY = 2; + public static final int MODE_DELETE = 3; + + private static String getTitle(Context context, int mode) { + switch(mode) { + case MODE_FLIP: + return context.getResources().getString(R.string.spoof_content_flip); + case MODE_GRAVITY: + return context.getResources().getString(R.string.spoof_gravity); + case MODE_DELETE: + return context.getResources().getString(R.string.spoof_delete); + default: + return "Unknown image spoof"; + } + } + private static String getDescription(Context context, int mode) { + switch(mode) { + case MODE_FLIP: + return context.getResources().getString(R.string.spoof_content_flip_description); + case MODE_GRAVITY: + return context.getResources().getString(R.string.spoof_gravity_description); + case MODE_DELETE: + return context.getResources().getString(R.string.spoof_delete_description); + default: + return ""; + } + } + + protected final int mode; + + private final String js; + + public ContentChange(Context context, int mode) { + super(getTitle(context, mode), getDescription(context, mode)); + this.mode = mode; + switch(mode) { + default: + case MODE_GRAVITY: + js = ""; + break; + case MODE_DELETE: + String payload = ""; + try { + payload = IOHelpers.readFileContents( + context.getResources().openRawResource(R.raw.js_removewords)); + } catch (NotFoundException e) { + Log.w(TAG, "Failed to load js_removewords payload", e); + } catch (IOException e) { + Log.w(TAG, "Failed to load js_removewords payload", e); + } + js = payload; + break; + } + } + + /** + * If using a custom mode it MUST NOT collide with existing modes. + * @param title + * @param description + * @param mode + */ + protected ContentChange(String title, String description, int mode) { + super(title, description); + js = ""; + this.mode = mode; + } + + @Override + protected void modifyDocument(Document document, Element body) { + switch(mode) { + default: // To allow custom implementations to pass through + case MODE_FLIP: + modifyElement(body); + break; + case MODE_GRAVITY: + case MODE_DELETE: + document.select("head").append(js); + break; + + } + } + + /** + * Recursively modifies an element according to mode. + * @param element + */ + private void modifyElement(Element element) { + for(Node node : element.childNodes()) { + if(node instanceof TextNode) { + modifyTextNode((TextNode) node); + } else if(node instanceof Element) { + modifyElement((Element) node); + } + } + } + + protected void modifyTextNode(TextNode node) { + switch(mode) { + case MODE_FLIP: + String reversed = + new StringBuilder(node.text()).reverse().toString(); + node.text(Lists.map(TitleChange.upsideDown, reversed)); + break; + } + } +} diff --git a/src/uk/digitalsquid/netspoofer/spoofs/CustomTextChange.java b/src/uk/digitalsquid/netspoofer/spoofs/CustomTextChange.java index 9b56c2a..6266107 100644 --- a/src/uk/digitalsquid/netspoofer/spoofs/CustomTextChange.java +++ b/src/uk/digitalsquid/netspoofer/spoofs/CustomTextChange.java @@ -24,8 +24,7 @@ import java.util.HashMap; import java.util.Map; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; +import org.jsoup.nodes.TextNode; import uk.digitalsquid.netspoofer.R; import android.app.AlertDialog; @@ -43,12 +42,14 @@ * @author Will Shackleton * */ -public class CustomTextChange extends HtmlEditorSpoof { +public class CustomTextChange extends ContentChange { private static final long serialVersionUID = 8490503138296852028L; + + private static final int MODE = 1005; - public CustomTextChange() { - // TODO: Localise - super("Text change", "Change all text on all websites"); + public CustomTextChange(Context context) { + super(context.getResources().getString(R.string.spoof_textchange), + context.getResources().getString(R.string.spoof_textchange_description), MODE); } private final Map changeValues = new HashMap(8); @@ -134,14 +135,19 @@ public void onClick(DialogInterface dialog, int which) { } @Override - public Map getCustomEnv() { - return changeValues; - } - - @Override - protected void modifyDocument(Document document, Element body) { - if(body != null) { - + protected void modifyTextNode(TextNode node) { + super.modifyTextNode(node); + switch(mode) { + case MODE: + String text = node.text(); + for(int i = 0 ; i < 8; i++) { + String from = changeValues.get(String.format("TEXT%dOLD", i)); + String to = changeValues.get(String.format("TEXT%dNEW", i)); + if(from != null && to != null) + text = text.replace(from, to); + } + node.text(text); + break; } } } diff --git a/src/uk/digitalsquid/netspoofer/spoofs/TitleChange.java b/src/uk/digitalsquid/netspoofer/spoofs/TitleChange.java index d9ac003..0ad50d3 100644 --- a/src/uk/digitalsquid/netspoofer/spoofs/TitleChange.java +++ b/src/uk/digitalsquid/netspoofer/spoofs/TitleChange.java @@ -7,6 +7,7 @@ import org.jsoup.select.Elements; import uk.digitalsquid.netspoofer.R; +import uk.digitalsquid.netspoofer.config.Lists; import android.content.Context; public class TitleChange extends HtmlEditorSpoof { @@ -52,13 +53,7 @@ protected void modifyDocument(Document document, Element body) { Element title = titles.first(); String reversed = new StringBuilder(title.text()).reverse().toString(); - StringBuilder result = new StringBuilder(reversed.length()); - for(char c : reversed.toCharArray()) { - Character ud = upsideDown.get(c); - if(ud == null) ud = c; - result.append(ud); - } - title.text(result.toString()); + title.text(Lists.map(upsideDown, reversed)); } break; case MODE_REVERSE: