// ==UserScript==
// @name gAES
// @description Encrypting your Google chats.
// @namespace gAES
// @include https://mail.google.com/mail/u/0/#inbox
// @include https://mail.google.com/mail/*
// @require http://code.jquery.com/jquery-1.9.1.min.js
// @require https://raw.github.com/mdp/gibberish-aes/master/dist/gibberish-aes-1.0.0.js
// @grant none
// @version 1
// ==/UserScript==
/**
* Nicolas Turlais
* 2013
* MIT Licence
* https://github.com/nicolas-t/gAES
* uses jQuery
* http://jquery.com/
* uses Gibberish AES
* Mark Percival
* https://github.com/mdp/gibberish-aes
*/
/* don't run the script on iframes */
if (window.top != window.self){
return;
}
jQuery(window).load(function(){
/*----- GLOBALS ------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------*/
/* @whiteList : The name of the user you want to chat with,and a random passphrase you share with him */
/*-------------------------------------------------------------------------------------------------------*/
/*-
//WhiteList exemple : 1 user
var whiteList = [{
user : 'Keith Haring',
passphrase : 'a-strong-passphrase'
}];
//WhiteList exemple : 2 users
var whiteList = [{
user : 'Stephen Shore',
passphrase : 'a-strong-passphrase'
},
{
user : 'Andy Warhol',
passphrase : 'another-strong-passphrase'
}];
-*/
var whiteList = [{
user : 'Firstname Surname', /* edit here */
passphrase : 'abcDEF-123456' /* edit here */
}];
/*-------------------------------------------------------------------------------------------------------*/
/* @matcherStart : character for detecting the begining of a encrypted string */
/* @matcherStop : character for detecting the end of a encrypted string */
/* @refresh : duration between two chat refreshing (in ms) */
/*-------------------------------------------------------------------------------------------------------*/
var matcherStart = '#',
matcherStop = '_',
refresh = 1000;
/*----- CHAT EVENTS ----------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* When the "Enter" key is pressed, if the user is whitelisted... */
/* Instead of sending the message we encrypt it... */
/* Then we submit it encrypted surrounded by the two matchers. */
/*------------------------------------------------------------------------------------------------------*/
jQuery(document).on('keydown', 'div.no textarea', function (e){
if(e.keyCode == 13){
var conversation = findConversation(jQuery(this));
var receiver = findReceiver(conversation);
var receiverIndex = isWhiteListed(receiver);
if(receiverIndex < 0 ){ return;}
var receiverPassphrase = whiteList[receiverIndex].passphrase;
var clearText = jQuery(this).val();
var encryptedText = GibberishAES.enc(clearText, receiverPassphrase).replace("\n", "");
jQuery(this).val(matcherStart + encryptedText + matcherStop);
}
});
/*------------------------------------------------------------------------------------------------------*/
/* We refresh the chat box every x miliseconds... */
/* In order to decrypt the encrypted messages (received or sent) */
/*------------------------------------------------------------------------------------------------------*/
setInterval(function(){
updateConversationsContent();
},refresh);
/*----- HISTORY EVENT ---------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* When viewing the chat history the URL changes to #chats/XXXXX */
/* We check is the viewed history belongs to whitelisted user */
/* If so we add a "Decrypt" button */
/*------------------------------------------------------------------------------------------------------*/
jQuery(window).on('hashchange', function() {
if (window.location.hash.substring(0, 7) == "#chats/") {
jQuery.each(whiteList, function(index, value){
if(testHistoryUser(value.user)){
createDecryptButton('h1.ha', index);
}
});
}
});
/*----- HISTORY FUNCTIONS -----------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* Tries to find a whitelisted user name in the
tag of the chat history page */
/*------------------------------------------------------------------------------------------------------*/
function testHistoryUser(user){
var str = jQuery('h1.ha').text();
var matcher = new RegExp("\\b" + user + "\\b", "g");
if(str.match(matcher)){
return true;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Creates a nice google blue button in @parent */
/* Bind a function (decryptHistory()) to click, passing whitelisted user @index as param */
/*------------------------------------------------------------------------------------------------------*/
function createDecryptButton(parent, index){
jQuery('',{'class' : 'T-I J-J5-Ji aOA T-I-atl'})
.html('Decrypt')
.appendTo(parent)
.on('click', index, decryptHistory)
.css({'position' : 'absolute' , 'top' : '-4px'});
}
/*------------------------------------------------------------------------------------------------------*/
/* loop trought all history messages and call the decrypt function */
/* @event.data contain the whitelisted user index (see createDecryptButton() for binding) */
/*------------------------------------------------------------------------------------------------------*/
function decryptHistory(event){
var receiverIndex = event.data;
findAllHistoryMessages().each(function(){
decrypt(whiteList[receiverIndex].passphrase, this);
});
}
/*----- CHAT FUNCTIONS -----------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* similar to indexOf or inArray */
/* returns the index of the user @s or -1 if no user found */
/*------------------------------------------------------------------------------------------------------*/
function isWhiteListed(s){
var r = -1;
jQuery.each(whiteList, function(index, value){
if(s == value.user){
r = index;
return false; //break the loop
}
});
return r;
}
/*------------------------------------------------------------------------------------------------------*/
/* Decypt all whitelisted conversations messages */
/*------------------------------------------------------------------------------------------------------*/
function updateConversationsContent(){
findAllConversations().each(function(){/*each conversation*/
var receiver = findReceiver(jQuery(this));
var receiverIndex = isWhiteListed(receiver);
if(receiverIndex < 0 ){ return;}
findAllMessages(jQuery(this)).each(function(){ /*each message*/
decrypt(whiteList[receiverIndex].passphrase, this);
});
});
}
/*----- CHAT & HISTORY FUNCTIONS -------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* uses the two matchers to detect encrypted messages in @str */
/* loops trought result, remove the matcherStart, stores and returns the clean encrypted messages */
/*------------------------------------------------------------------------------------------------------*/
function getMatches(str){
var matcher = new RegExp(matcherStart + "([\\s\\S]*?)(?=" + matcherStop + ")", "g");
var result = str.match(matcher);
var r = [];
if(result){
for (var i = 0; i < result.length; i++) {
if (result[i].length > 0) {
r.push(result[i].substring(1, result[i].length));
}
}
}
return r;
}
/*------------------------------------------------------------------------------------------------------*/
/* Get encrypted strings with getMatches() in @elem */
/* Then for each one decrypts it with @receiverPassphrase */
/* linkify it and adds it to @elem */
/*------------------------------------------------------------------------------------------------------*/
function decrypt(receiverPassphrase, elem){
var $message = jQuery(elem);
var clearStr = $message.text();
var encryptedStr = getMatches(clearStr);
jQuery.each(encryptedStr, function(k,v){ /*each encrypted string in a message*/
var textDecrypt = GibberishAES.dec(v, receiverPassphrase).replace("\n", "");
var textClear = clearStr.replace(matcherStart + v + matcherStop, textDecrypt);
var textParsed = linkify(textClear);
$message.html(textParsed);
});
}
/*----- MESSAGES PARSING ---------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------------*/
/* Detects links in @text and replaces it with html markup for links */
/*------------------------------------------------------------------------------------------------------*/
function linkify(text) {
// todo : add the different gtalk possibilities : bold, underline, italic...
text = text.replace(/(https?:\/\/\S+)/gi, function (s) {
return '' + s + '';
});
return text;
}
/*----- DOM SELECTIONS ------------------------------------------------------------------------*/
function findReceiver($conversation){
return $conversation.find('.aCk .nH.aBp .cf.Ht .Hp').text();
}
function findAllMessages($conversation){
return $conversation.find("[role='chatMessage'] div.kl, [role='chatMessage'] span[dir='ltr']")
}
function findConversation($children){
return $children.parents(".nH.Hd[role='dialog']");
}
function findAllConversations(){
return jQuery(".nH.Hd[role='dialog']");
}
function findAllHistoryMessages(){
return jQuery("[data-type='m']");
}
});