mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 17:02:17 -05:00
[WO-237] integrate web worker support for pgp
This commit is contained in:
parent
6ec7040a2e
commit
1da5c68fd1
31
package.json
31
package.json
@ -17,21 +17,20 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular": "https://github.com/angular/angular.js/tarball/v1.2.8",
|
"angular": "https://github.com/angular/angular.js/tarball/v1.2.8",
|
||||||
"grunt": "0.4.1",
|
"grunt": "~0.4.1",
|
||||||
"mocha": "1.13.0",
|
"mocha": "~1.13.0",
|
||||||
"phantomjs": "1.9.1-9",
|
"chai": "~1.7.2",
|
||||||
"chai": "1.7.2",
|
"sinon": "~1.7.3",
|
||||||
"sinon": "1.7.3",
|
"grunt-contrib-connect": "~0.5.0",
|
||||||
"grunt-contrib-connect": "0.5.0",
|
"grunt-contrib-jshint": "~0.6.4",
|
||||||
"grunt-contrib-jshint": "0.6.4",
|
"grunt-contrib-qunit": "~0.2.2",
|
||||||
"grunt-contrib-qunit": "0.2.2",
|
"grunt-mocha": "~0.4.1",
|
||||||
"grunt-mocha": "0.4.1",
|
"grunt-contrib-clean": "~0.5.0",
|
||||||
"grunt-contrib-clean": "0.5.0",
|
"grunt-csso": "~0.5.0",
|
||||||
"grunt-csso": "0.5.0",
|
"grunt-contrib-sass": "~0.5.0",
|
||||||
"grunt-contrib-sass": "0.5.0",
|
"grunt-autoprefixer": "~0.3.0",
|
||||||
"grunt-autoprefixer": "0.3.0",
|
"grunt-contrib-watch": "~0.5.3",
|
||||||
"grunt-contrib-watch": "0.5.3",
|
"grunt-contrib-copy": "~0.4.1",
|
||||||
"grunt-contrib-copy": "0.4.1",
|
"grunt-contrib-compress": "~0.5.2"
|
||||||
"grunt-contrib-compress": "0.5.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,15 +5,18 @@ define(function(require) {
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var openpgp = require('openpgp'),
|
var openpgp = require('openpgp'),
|
||||||
util = require('openpgp').util;
|
util = require('openpgp').util,
|
||||||
|
config = require('js/app-config').config;
|
||||||
|
|
||||||
var PGP = function() {};
|
var PGP = function() {
|
||||||
|
openpgp.initWorker(config.workerPath + '/../lib/openpgp/openpgp.worker.js');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a key pair for the user
|
* Generate a key pair for the user
|
||||||
*/
|
*/
|
||||||
PGP.prototype.generateKeys = function(options, callback) {
|
PGP.prototype.generateKeys = function(options, callback) {
|
||||||
var keys, userId;
|
var userId;
|
||||||
|
|
||||||
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize || typeof options.passphrase !== 'string') {
|
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize || typeof options.passphrase !== 'string') {
|
||||||
callback({
|
callback({
|
||||||
@ -23,13 +26,14 @@ define(function(require) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate keypair (keytype 1=RSA)
|
// generate keypair (keytype 1=RSA)
|
||||||
try {
|
|
||||||
userId = 'Whiteout User <' + options.emailAddress + '>';
|
userId = 'Whiteout User <' + options.emailAddress + '>';
|
||||||
keys = openpgp.generateKeyPair(1, options.keySize, userId, options.passphrase);
|
openpgp.generateKeyPair(1, options.keySize, userId, options.passphrase, onGenerated);
|
||||||
} catch (e) {
|
|
||||||
|
function onGenerated(err, keys) {
|
||||||
|
if (err) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Keygeneration failed!',
|
errMsg: 'Keygeneration failed!',
|
||||||
err: e
|
err: err
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -39,6 +43,7 @@ define(function(require) {
|
|||||||
privateKeyArmored: keys.privateKeyArmored,
|
privateKeyArmored: keys.privateKeyArmored,
|
||||||
publicKeyArmored: keys.publicKeyArmored
|
publicKeyArmored: keys.publicKeyArmored
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -160,7 +165,7 @@ define(function(require) {
|
|||||||
* Encrypt and sign a pgp message for a list of receivers
|
* Encrypt and sign a pgp message for a list of receivers
|
||||||
*/
|
*/
|
||||||
PGP.prototype.encrypt = function(plaintext, publicKeysArmored, callback) {
|
PGP.prototype.encrypt = function(plaintext, publicKeysArmored, callback) {
|
||||||
var ciphertext, publicKeys = [];
|
var publicKeys = [];
|
||||||
|
|
||||||
// check keys
|
// check keys
|
||||||
if (!this._privateKey || publicKeysArmored.length < 1) {
|
if (!this._privateKey || publicKeysArmored.length < 1) {
|
||||||
@ -170,13 +175,11 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
// parse armored public keys
|
// parse armored public keys
|
||||||
|
try {
|
||||||
publicKeysArmored.forEach(function(pubkeyArmored) {
|
publicKeysArmored.forEach(function(pubkeyArmored) {
|
||||||
publicKeys.push(openpgp.key.readArmored(pubkeyArmored).keys[0]);
|
publicKeys.push(openpgp.key.readArmored(pubkeyArmored).keys[0]);
|
||||||
});
|
});
|
||||||
// encrypt and sign the plaintext
|
|
||||||
ciphertext = openpgp.signAndEncryptMessage(publicKeys, this._privateKey, plaintext);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Error encrypting plaintext!',
|
errMsg: 'Error encrypting plaintext!',
|
||||||
@ -185,14 +188,15 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, ciphertext);
|
// encrypt and sign the plaintext
|
||||||
|
openpgp.signAndEncryptMessage(publicKeys, this._privateKey, plaintext, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt and verify a pgp message for a single sender
|
* Decrypt and verify a pgp message for a single sender
|
||||||
*/
|
*/
|
||||||
PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
|
PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
|
||||||
var publicKey, message, decrypted, signaturesValid;
|
var publicKey, message, signaturesValid;
|
||||||
|
|
||||||
// check keys
|
// check keys
|
||||||
if (!this._privateKey || !publicKeyArmored) {
|
if (!this._privateKey || !publicKeyArmored) {
|
||||||
@ -202,11 +206,10 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt and verify pgp message
|
// read keys and ciphertext message
|
||||||
try {
|
try {
|
||||||
publicKey = openpgp.key.readArmored(publicKeyArmored).keys[0];
|
publicKey = openpgp.key.readArmored(publicKeyArmored).keys[0];
|
||||||
message = openpgp.message.readArmored(ciphertext);
|
message = openpgp.message.readArmored(ciphertext);
|
||||||
decrypted = openpgp.decryptAndVerifyMessage(this._privateKey, [publicKey], message);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Error decrypting PGP message!',
|
errMsg: 'Error decrypting PGP message!',
|
||||||
@ -215,6 +218,10 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decrypt and verify pgp message
|
||||||
|
openpgp.decryptAndVerifyMessage(this._privateKey, [publicKey], message, onDecrypted);
|
||||||
|
|
||||||
|
function onDecrypted(err, decrypted) {
|
||||||
// check if signatures are valid
|
// check if signatures are valid
|
||||||
signaturesValid = true;
|
signaturesValid = true;
|
||||||
decrypted.signatures.forEach(function(sig) {
|
decrypted.signatures.forEach(function(sig) {
|
||||||
@ -231,6 +238,7 @@ define(function(require) {
|
|||||||
|
|
||||||
// return decrypted plaintext
|
// return decrypted plaintext
|
||||||
callback(null, decrypted.text);
|
callback(null, decrypted.text);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return PGP;
|
return PGP;
|
||||||
|
10
src/lib/openpgp/openpgp.min.js
vendored
10
src/lib/openpgp/openpgp.min.js
vendored
File diff suppressed because one or more lines are too long
157
src/lib/openpgp/openpgp.worker.js
Normal file
157
src/lib/openpgp/openpgp.worker.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
|
// 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
|
||||||
|
|
||||||
|
window = {}; // to make UMD bundles work
|
||||||
|
|
||||||
|
importScripts('openpgp.min.js');
|
||||||
|
|
||||||
|
var MIN_SIZE_RANDOM_BUFFER = 40000;
|
||||||
|
var MAX_SIZE_RANDOM_BUFFER = 60000;
|
||||||
|
|
||||||
|
window.openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER);
|
||||||
|
|
||||||
|
onmessage = function (event) {
|
||||||
|
var data = null,
|
||||||
|
err = null,
|
||||||
|
msg = event.data,
|
||||||
|
correct = false;
|
||||||
|
switch (msg.event) {
|
||||||
|
case 'seed-random':
|
||||||
|
window.openpgp.crypto.random.randomBuffer.set(msg.buf);
|
||||||
|
break;
|
||||||
|
case 'encrypt-message':
|
||||||
|
try {
|
||||||
|
msg.keys = msg.keys.map(packetlistCloneToKey);
|
||||||
|
data = window.openpgp.encryptMessage(msg.keys, msg.text);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'sign-and-encrypt-message':
|
||||||
|
try {
|
||||||
|
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
|
||||||
|
msg.privateKey = packetlistCloneToKey(msg.privateKey);
|
||||||
|
data = window.openpgp.signAndEncryptMessage(msg.publicKeys, msg.privateKey, msg.text);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'decrypt-message':
|
||||||
|
try {
|
||||||
|
msg.privateKey = packetlistCloneToKey(msg.privateKey);
|
||||||
|
msg.message = packetlistCloneToMessage(msg.message.packets);
|
||||||
|
data = window.openpgp.decryptMessage(msg.privateKey, msg.message);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'decrypt-and-verify-message':
|
||||||
|
try {
|
||||||
|
msg.privateKey = packetlistCloneToKey(msg.privateKey);
|
||||||
|
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
|
||||||
|
msg.message = packetlistCloneToMessage(msg.message.packets);
|
||||||
|
data = window.openpgp.decryptAndVerifyMessage(msg.privateKey, msg.publicKeys, msg.message);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'sign-clear-message':
|
||||||
|
try {
|
||||||
|
msg.privateKeys = msg.privateKeys.map(packetlistCloneToKey);
|
||||||
|
data = window.openpgp.signClearMessage(msg.privateKeys, msg.text);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'verify-clear-signed-message':
|
||||||
|
try {
|
||||||
|
msg.publicKeys = msg.publicKeys.map(packetlistCloneToKey);
|
||||||
|
var packetlist = window.openpgp.packet.List.fromStructuredClone(msg.message.packets);
|
||||||
|
msg.message = new window.openpgp.cleartext.CleartextMessage(msg.message.text, packetlist);
|
||||||
|
data = window.openpgp.verifyClearSignedMessage(msg.publicKeys, msg.message);
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'generate-key-pair':
|
||||||
|
try {
|
||||||
|
data = window.openpgp.generateKeyPair(msg.keyType, msg.numBits, msg.userId, msg.passphrase);
|
||||||
|
data.key = data.key.toPacketlist();
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'decrypt-key':
|
||||||
|
try {
|
||||||
|
msg.privateKey = packetlistCloneToKey(msg.privateKey);
|
||||||
|
correct = msg.privateKey.decrypt(msg.password);
|
||||||
|
if (correct) {
|
||||||
|
data = msg.privateKey.toPacketlist();
|
||||||
|
} else {
|
||||||
|
err = 'Wrong password';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
case 'decrypt-key-packet':
|
||||||
|
try {
|
||||||
|
msg.privateKey = packetlistCloneToKey(msg.privateKey);
|
||||||
|
msg.keyIds = msg.keyIds.map(window.openpgp.Keyid.fromClone);
|
||||||
|
correct = msg.privateKey.decryptKeyPacket(msg.keyIds, msg.password);
|
||||||
|
if (correct) {
|
||||||
|
data = msg.privateKey.toPacketlist();
|
||||||
|
} else {
|
||||||
|
err = 'Wrong password';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
err = e.message;
|
||||||
|
}
|
||||||
|
response({event: 'method-return', data: data, err: err});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown Worker Event.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function response(event) {
|
||||||
|
if (window.openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) {
|
||||||
|
postMessage({event: 'request-seed'});
|
||||||
|
}
|
||||||
|
postMessage(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function packetlistCloneToKey(packetlistClone) {
|
||||||
|
var packetlist = window.openpgp.packet.List.fromStructuredClone(packetlistClone);
|
||||||
|
return new window.openpgp.key.Key(packetlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
function packetlistCloneToMessage(packetlistClone) {
|
||||||
|
var packetlist = window.openpgp.packet.List.fromStructuredClone(packetlistClone);
|
||||||
|
return new window.openpgp.message.Message(packetlist);
|
||||||
|
}
|
||||||
|
},{}]},{},[1])
|
||||||
|
;
|
@ -17,7 +17,7 @@ require(['../../src/require-config'], function() {
|
|||||||
|
|
||||||
// Start the main app logic.
|
// Start the main app logic.
|
||||||
require(['js/app-config'], function(app) {
|
require(['js/app-config'], function(app) {
|
||||||
window.Worker = undefined; // disable web workers since mocha doesn't support them
|
//window.Worker = undefined; // disable web workers since mocha doesn't support them
|
||||||
|
|
||||||
app.config.workerPath = '../../src/js';
|
app.config.workerPath = '../../src/js';
|
||||||
|
|
||||||
|
@ -5,13 +5,15 @@ define(function(require) {
|
|||||||
expect = chai.expect;
|
expect = chai.expect;
|
||||||
|
|
||||||
describe('PGP Crypto Api unit tests', function() {
|
describe('PGP Crypto Api unit tests', function() {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
var pgp,
|
var pgp,
|
||||||
user = 'whiteout.test@t-online.de',
|
user = 'whiteout.test@t-online.de',
|
||||||
passphrase = 'asdf',
|
passphrase = 'asdf',
|
||||||
keySize = 512,
|
keySize = 512,
|
||||||
keyId = 'F6F60E9B42CDFF4C',
|
keyId = 'F6F60E9B42CDFF4C',
|
||||||
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
|
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
|
||||||
'Version: OpenPGP.js v0.3.0\r\n' +
|
'Version: OpenPGP.js v0.4.0\r\n' +
|
||||||
'Comment: http://openpgpjs.org\r\n' +
|
'Comment: http://openpgpjs.org\r\n' +
|
||||||
'\r\n' +
|
'\r\n' +
|
||||||
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
|
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
|
||||||
@ -22,7 +24,7 @@ define(function(require) {
|
|||||||
'=6XMW\r\n' +
|
'=6XMW\r\n' +
|
||||||
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n',
|
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n',
|
||||||
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' +
|
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' +
|
||||||
'Version: OpenPGP.js v0.3.0\r\n' +
|
'Version: OpenPGP.js v0.4.0\r\n' +
|
||||||
'Comment: http://openpgpjs.org\r\n' +
|
'Comment: http://openpgpjs.org\r\n' +
|
||||||
'\r\n' +
|
'\r\n' +
|
||||||
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' +
|
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' +
|
||||||
|
@ -10,7 +10,7 @@ require(['../../src/require-config'], function() {
|
|||||||
require(['js/app-config', 'cordova'], function(app) {
|
require(['js/app-config', 'cordova'], function(app) {
|
||||||
// clear session storage of failed tests, so async order is correct after fail & refresh
|
// clear session storage of failed tests, so async order is correct after fail & refresh
|
||||||
window.sessionStorage.clear();
|
window.sessionStorage.clear();
|
||||||
window.Worker = undefined;
|
//window.Worker = undefined;
|
||||||
|
|
||||||
app.config.workerPath = '../../src/js';
|
app.config.workerPath = '../../src/js';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user