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: