Skip to content

Commit

Permalink
adding restructured GPG4Browsers code
Browse files Browse the repository at this point in the history
- created a test suite available at test/index.html
- fixed a bug in MD5 calculation
  • Loading branch information
Carsten Wentzlow committed Dec 9, 2011
1 parent 0526a24 commit 81212f2
Show file tree
Hide file tree
Showing 57 changed files with 13,985 additions and 0 deletions.
502 changes: 502 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

133 changes: 133 additions & 0 deletions plugins/chrome/background.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript">
//GPG4Browsers - An OpenPGP implementation in javascript
//Copyright (C) 2011 Recurity Labs GmbH
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

var tab_registry = new Array();

var account_name = null;

/**
* Event listener for chrom.extension message interface.
* This is the main data exchange interface for communication between windows.
*/
function onRequest(request, sender, sendResponse) {
// only the extension itself
if (document.URL.split("/")[2] != sender.id)
return;

/* the following code is currently not working, but a check for incognito mode would be nice to have here.
if (chrome.extension.inIncognitoContext != true)
alert("enable incognito mode for GPG4Browsers Extension!"+JSON.stringify(chrome.extension.inIncognitoContext));
*/


// Show the page action for the tab that the sender (content script)
// was on.
if (tab_registry[sender.tab.id] != null) {

sendResponse(tab_registry[sender.tab.id]);
tab_registry[sender.tab.id] = null;
return;
}
// page action... open the pgp tab with compose
if (request.action == 0) {
openComposeWindow(request);
sendResponse({});
return;
}
// request from contentscript on gmail interface to open a openpgp window with a message to decrypt/verify
if (request.action == 1) {
openComposeWindow(request);
sendResponse({});
return;
}

// openpgp is requesting to open a gmail compose window
if (request.action == 2 && sender.tab.id) {
openGmailComposeWindow(request);
sendResponse({});
return;
}
// contentscript on gmail compose window requesting the message
// not used due to missing implemenation
if (request.action == 3 && sender.tab.id) {
sendResponse(tab_registry[sender.tab.id]);
return;
}

account_name = request.account;
chrome.pageAction.show(sender.tab.id);

// Return nothing to let the connection be cleaned up.
sendResponse({});
}

chrome.pageAction.onClicked.addListener(pageActionListener);

/**
* opens the Gmail ComposeWindow and transmits the email data
* @param to string of recipient email addresses separated by ", "
* @param cc string of recipient email addresses separated by ", " receiving a copy
* @param cc string of recipient email addresses separated by ", " receiving a blind copy
* @param subject email subject as string
*/
function openGmailComposeWindow(request) {
var tab = chrome.tabs.create(
{url: "https://mail.google.com/mail/?view=cm&fs=1&tf=1&to="+
encodeURIComponent(request.to)+"&cc="+
encodeURIComponent(request.cc)+"&bcc="+
encodeURIComponent(request.bcc)+"&su="+
encodeURIComponent(request.subject)+"&body="+
// TODO: long bodys result in an error on the google mail server because the URL gets too long
encodeURIComponent(request.body)+"&shva=1", selected: true});
// its a good idea to store the request...
// once the gmail compose window has opened, the content
// script could fetch the request to insert message data
// into the forms this would be a proper solution to the
// "url too long" issue. Problem: the page is rendered
// within an iframe so contentscript has no access to
// fill in the data. We have'nt tried the basic html
// approach yet.. see action == "3"
tab_registry[tab.id] = request;
}

/**
* the page action listener event handler:
* opens a compose window (openpgp.html)
*/
function pageActionListener(tab) {
openComposeWindow({action: 0, account: account_name});
}

/**
*
*/
function openComposeWindow(request) {
var tab = chrome.tabs.create({url: "openpgp.html", selected: true }, function(tab) {
tab_registry[tab.id] = request;
});
}

// Listen for the content script to send a message to the background page.
chrome.extension.onRequest.addListener(onRequest);
</script>
</head>
</html>
244 changes: 244 additions & 0 deletions plugins/chrome/contentscripts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA


if (window.location.href.indexOf("https://mail.google.com/mail/?view=cm") == 0) {
// we are running in the compose window
} else {
// we are running in the normal interface
chrome.extension.sendRequest({account: document.getElementsByTagName("script")[4].text.split(",")[10].replace(/"/g,"").trim()}, function(response) {});

}

var current_message_type = -1;
var current_message = null;

/**
* searches the given text for a pgp message. If a message is available the openpgp message dialog is shown
* @param text text to be searched
*/
function find_openpgp(text) {
text = text.replace(/\r\n/g,"\n");
if (document.location.hash != current_message) {
if (/-----BEGIN PGP MESSAGE-----/.test(text) && /-----END PGP MESSAGE-----/.test(text)) {
current_message= document.location.hash;
current_message_type = 0;
current_pgp_block = text.substring(text.indexOf("-----BEGIN PGP MESSAGE-----"), text.indexOf("-----END PGP MESSAGE-----")+25);
current_pgp_block = current_pgp_block.replace(/\n/g,"").replace(/<br>/g,"\n").replace(/<wbr>/g,"");
if (pgp_verifyCheckSum(current_pgp_block))
show_pgp_alert();

} else if (/-----BEGIN PGP SIGNED MESSAGE-----/.test(text) && /-----END PGP SIGNATURE-----/.test(text)) {
current_message= document.location.hash;
current_message_type = 1;
current_pgp_block = text.substring(text.indexOf("-----BEGIN PGP SIGNED MESSAGE-----"), text.indexOf("-----END PGP SIGNATURE-----")+26);
current_pgp_block = current_pgp_block.replace(/\n/g,"").replace(/<br>/g,"\n").replace(/<wbr>/g,"");
if (pgp_verifyCheckSum(current_pgp_block.substring(current_pgp_block.indexOf("-----BEGIN PGP SIGNATURE-----"))))
show_pgp_alert();
} else {
hide_pgp_alert();
}
}
}

var doc = null;

/**
* call routine to open the openpgp.html page for handling a message
* @return null
*/
function start_pgp_dialog() {
//Gmail does not provide a generic way. to get message data out of the HTML interface so we parse the DOM
Gmail.getMail(function(msg) {
msg.action = 1;
chrome.extension.sendRequest(msg, function(response) {
// hide_pgp_alert(); // hide pgp alert after opening the openpgp window
});
});
}

/**
* showing the pgp alert
* @return
*/
function show_pgp_alert() {
var div = document.createElement("div");
var buttonyes = document.createElement("button");
var buttonno = document.createElement("button");
buttonyes.setAttribute("type", "submit");
buttonyes.addEventListener("mousedown", function () {
var msg = start_pgp_dialog();
});
buttonno.setAttribute("type", "submit");
buttonno.addEventListener("mousedown", function() { hide_pgp_alert(); }, true);
buttonyes.appendChild(document.createTextNode("Yes"));
buttonno.appendChild(document.createTextNode("No"));
div.setAttribute("id", "gpg4browsers_alert");
div.setAttribute("style","position: fixed; top: 0px; width: 100%; background-color: #eeeeff; border-bottom: 1px solid #aaa;");
if (current_message_type == 0)
div.appendChild(document.createTextNode("This mail is encrypted. Do you want to open it with GPG4Browsers?"));
else if (current_message_type == 1)
div.appendChild(document.createTextNode("This mail is signed. Do you want to open it with GPG4Browsers?"));
div.appendChild(buttonyes);
div.appendChild(buttonno);
document.body.appendChild(div);
};

/**
* hiding the pgp alert
* @return
*/
function hide_pgp_alert() {
if (document.getElementById("gpg4browsers_alert") != null) {
document.getElementById("gpg4browsers_alert").parentNode.removeChild(document.getElementById("gpg4browsers_alert"));
}
}

/**
* background process timer to constantly check the displayed page for pgp messages
*/
window.setInterval(function() {
find_openpgp(document.body.innerHTML);
if (document.getElementById("canvas_frame") != null)
find_openpgp(document.getElementById("canvas_frame").contentDocument.body.innerHTML);
}, 1000);


/**
* verifies the checksum of an base64 encrypted pgp block
* @param text containing the base64 block and the base64 encoded checksum
* @return true if the checksum was correct, false otherwise
*/
function pgp_verifyCheckSum(text) {
var splittedtext = text.split('-----');
var data = r2s(splittedtext[2].split('\n\n')[1].split("\n=")[0]);
var checksum = splittedtext[2].split('\n\n')[1].split("\n=")[1].replace(/\n/g,"");
var c = getCheckSum(data);
var d = checksum;
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
}

/**
* calculates the checksum over a given block of data
* @param data block to be used
* @return a string containing the base64 encoded checksum
*/
function getCheckSum(data) {
var c = createcrc24(data);
var str = "" + String.fromCharCode(c >> 16)+
String.fromCharCode((c >> 8) & 0xFF)+
String.fromCharCode(c & 0xFF);
return s2r(str);
}


/**
* calculation routine for a CRC-24 checksum
* @param data
* @return
*/
function createcrc24 (data) {
var crc = 0xB704CE;
var i;
var mypos = 0;
var len = data.length;
while (len--) {
crc ^= (data[mypos++].charCodeAt()) << 16;
for (i = 0; i < 8; i++) {
crc <<= 1;
if (crc & 0x1000000)
crc ^= 0x1864CFB;
}
}
return crc & 0xFFFFFF;
}

// base64 implementation

var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

/**
* Converting Base64 data to a string
* @param t base64 encoded data string
* @return data string
*/
function r2s(t) {
var c, n;
var r = '', s = 0, a = 0;
var tl = t.length;

for (n = 0; n < tl; n++) {
c = b64s.indexOf(t.charAt(n));
if (c >= 0) {
if (s)
r += String.fromCharCode(a | (c >> (6 - s)) & 255);
s = (s + 2) & 7;
a = (c << s) & 255;
}
}
return r;
}

/**
* Converting a data string to a base64 encoded string
* @param t data string
* @return base64 encoded data string
*/
function s2r(t) {
var a, c, n;
var r = '', l = 0, s = 0;
var tl = t.length;

for (n = 0; n < tl; n++) {
c = t.charCodeAt(n);
if (s == 0) {
r += b64s.charAt((c >> 2) & 63);
a = (c & 3) << 4;
} else if (s == 1) {
r += b64s.charAt((a | (c >> 4) & 15));
a = (c & 15) << 2;
} else if (s == 2) {
r += b64s.charAt(a | ((c >> 6) & 3));
l += 1;
if ((l % 60) == 0)
r += "\n";
r += b64s.charAt(c & 63);
}
l += 1;
if ((l % 60) == 0)
r += "\n";

s += 1;
if (s == 3)
s = 0;
}
if (s > 0) {
r += b64s.charAt(a);
l += 1;
if ((l % 60) == 0)
r += "\n";
r += '=';
l += 1;
}
if (s == 1) {
if ((l % 60) == 0)
r += "\n";
r += '=';
}

return r;
}
18 changes: 18 additions & 0 deletions plugins/chrome/jquery.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit 81212f2

Please sign in to comment.