// ==UserScript==
// @name ScareMail
// @version 1.0.1
// @namespace ScareMail
// @description Makes email "scary" in order to disrupt NSA surveillance
//
// @match *://mail.google.com/*
// @include *://mail.google.com/*
//
// ==/UserScript==// -----------------------------------------
//
// ------------------------------------------------------------
// ScareMail
// by Benjamin Grosser
// http://bengrosser.com
//
// Version 1.0.1 (for Gmail)
// http://bengrosser.com/projects/scaremail/
//
// Premiere Exhibition:
// 2013 PRISM Break-Up, Eyebeam, NYC
// http://prismbreakup.org
//
// Many thanks to the PRISM Break-Up team for their support
// of the project!
// ------------------------------------------------------------
// ------------------------------------------------------------
// Third-Party Sources/Libraries/Algorithms
//
// ScareMail utilizes some third party libraries and
// algorithms.
//
// I use pattern.en and NLTK for natural language processing:
//
// http://www.clips.ua.ac.be/pages/pattern-en
// http://nltk.org
//
// I utilize Markov-chain style text generation as described by
// Kernighan and Pike in their book 'The Practice of Programming,'
// Copyright 1999, Lucent Technologies. (They allow use of their
// code for any purpose as long as the copyright appears here).
// I also owe thanks to Cheng Zhang for inspiring my Javascript
// translation of the Kernighan/Pike code.
//
// http://cm.bell-labs.com/cm/cs/tpop/code.html
//
// Finally, for this and other recent projects, I have been
// using Brock Adams' waitForKeyElements():
//
// https://gist.github.com/BrockA/2625891
// ------------------------------------------------------------
// ------------------------------------------------------------
// Text Sources
//
// ScareMail generates algorithmically unique stories each time
// it runs. These stories are several steps removed from an
// original source, namely "Fahrenheit 451" by Ray Bradbury.
//
// One of the primary transformations of that source text is
// made by substituting its nouns and verbs from those found
// in a recently released Homeland Security Analyst document:
//
// https://epic.org/foia/epic-v-dhs-media-monitoring/Analyst-Desktop-Binder-REDACTED.pdf
//
// Contained within this code resides several of these
// transformations.
// ------------------------------------------------------------
// constants
var ELEMENT_POLL_SPEED = 500; // element check interval in ms
var VERSION_NUMBER = '1.0.1';
var SCAREMAIL_HOME_URL= 'http://bengrosser.com/projects/scaremail/';
var GROSSER_URL= 'http://bengrosser.com/';
var IS_FIREFOX_ADDON = false;
var MIN_STORY_LENGTH = 400;
var MAX_STORY_LENGTH = 1000;
var j; // jQuery
// obvious header option
var scaremailheader =
" -- "+
"Following Text Generated by "+
"ScareMail
";
var scarystory = "";
function main() {
console.log("working on ---> "+window.location.href);
// setup jQuery on j to avoid any possible conflicts
j = jQuery.noConflict();
// watch for a new Gmail compose window, call addScaryStory() when found
waitForKeyElements('.LW-avf', addScaryStory, false);
waitForKeyElements('#gbzc', insertNavItem, true); // old menu style
waitForKeyElements('#gbwa', insertAppItem, true); // new menu style
// generates a new "scary" story and adds it to the email signature (if not
// already present)
function addScaryStory(jnode) {
// checks to see if the scaremailheader already exists, if it doesn't,
// generates a new scary story and adds to the email signature
if(!jnode.text().contains("Following Text Generated by ScareMail")) {
var storylength = getRandomInt(MIN_STORY_LENGTH,MAX_STORY_LENGTH);
scarystory = getScaryStory(storylength);
jnode.append('
'+scaremailheader+scarystory+'
');
}
}
}
function getDialogHTML() {
// Facebook Like Button for the ScareMail Project Homepage
var likebutton =
'';
// add a Twitter button
//likebutton += 'Tweet';
// FB and Twitter
var likebuttons =
'Tweet';
// FF bugging out on Twitter button, will figure out later
if(IS_FIREFOX_ADDON) likesection = likebutton;
else likesection = likebuttons;
var dialoghtml = '
';
return dialoghtml;
}
// for the new Google app launcher style menubar (not universal yet)
function insertAppItem() {
if(j('.scaremailnav').length == 0) {
j('#gbwa ul.gb_eb').append('
');
j('body').append(getDialogHTML());
j('#scaremaillink').click(function() {
console.log("clicked on scaremail link");
j('#modaldialog').modal({
opacity:65,
overlayClose:true,
overlayCss: {backgroundColor:"#000"}
});
});
}
}
// old style nav bar app launcher for Google/Gmail
function insertNavItem() {
// insert nav menu item for ScareMail
if(j('.scaremailnav').length == 0) {
j('#gbzc').append('
')
j('body').append(getDialogHTML());
j('#scaremaillink').click(function() {
console.log("clicked on scaremail link");
j('#modaldialog').modal({
opacity:65,
overlayClose:true,
overlayCss: {backgroundColor:"#000"}
});
});
}
}
// Markov-Chain Text Generation
var prefix;
var dict;
var order = 2;
function initprefix() {
prefix = new Array(order);
for (var i = 0; i < order; i++) prefix[i] = " ";
}
function add(s) {
key = prefix.join("#");
if (dict[key] == null) dict[key] = new Array();
dict[key].push(s);
prefix.shift();
prefix.push(s);
}
function gen(n) {
initprefix();
var out = "";
for (var i = 0; i < n; i++) {
var words = dict[ prefix.join("#") ];
var word = choice(words);
if (word == " ") break;
out += word + " "
prefix.shift();
prefix.push(word);
}
return out;
}
function choice(choices) {
index = Math.floor(Math.random() * choices.length);
return choices[index];
}
function getScaryStory(numwords) {
var inp = choice(INPUTFILES);
// split text into tokens
inp = inp.split(" ");
initprefix();
dict = new Array();
for (var i = 0; i < inp.length; i++)
add(inp[i]);
add(" ");
return gen(numwords);
}
// Utility
//
//
String.prototype.contains = function(it) { return this.indexOf(it) != -1; };
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function waitForKeyElements (selectorTxt, actionFunction, bWaitOnce, iframeSelector ) {
var targetNodes, btargetsFound;
targetNodes = j(selectorTxt);
if (targetNodes && targetNodes.length > 0) {
btargetsFound = true;
// found target node(s). go through each and act if they are new.
targetNodes.each ( function () {
var jThis = j(this);
var alreadyFound = jThis.data ('alreadyFound') || false;
if (!alreadyFound) {
// call the payload function.
//unsafeWindow.console.log("waitFor got a new element: "+selectorTxt);
var cancelFound = actionFunction (jThis);
if (cancelFound) btargetsFound = false;
else jThis.data ('alreadyFound', true);
}
} );
}
else {
btargetsFound = false;
}
// get the timer-control variable for this selector.
var controlObj = waitForKeyElements.controlObj || {};
var controlKey = selectorTxt.replace (/[^\w]/g, "_");
var timeControl = controlObj [controlKey];
// now set or clear the timer as appropriate.
if (btargetsFound && bWaitOnce && timeControl) {
// the only condition where we need to clear the timer.
clearInterval (timeControl);
delete controlObj [controlKey]
}
else {
// set a timer, if needed.
if (!timeControl) {
timeControl = setInterval ( function () {
waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
}, ELEMENT_POLL_SPEED
);
controlObj [controlKey] = timeControl;
}
}
waitForKeyElements.controlObj = controlObj;
}
/*
* pasting jQuery right into the script for speed and security reasons
* if you're worried whether there's anything nefarious in there, just
* delete everything below this and replace it with a new copy fresh
* from jquery.com. i used 1.7.2 in development so I can't guarantee
* any other version * will work
*/
/*! jQuery v1.7.2 jquery.com | jquery.org/license */
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="