245 lines
7.2 KiB
JavaScript
245 lines
7.2 KiB
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
|
|
|
|
|
|
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 OpenPGP.js?"));
|
|
else if (current_message_type == 1)
|
|
div.appendChild(document.createTextNode("This mail is signed. Do you want to open it with OpenPGP.js?"));
|
|
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;
|
|
}
|