Merge pull request #120 from whiteout-io/mocha
Add travis CI job and mocha tests in phantomjs
This commit is contained in:
commit
a3ab946d6a
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
resources/openpgpjs.pem
|
resources/openpgpjs.pem
|
||||||
build/
|
build/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
test/integration/lib
|
5
.travis.yml
Normal file
5
.travis.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.10"
|
||||||
|
before_install:
|
||||||
|
- npm install -g grunt-cli
|
52
Gruntfile.js
Normal file
52
Gruntfile.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
module.exports = function(grunt) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Project configuration.
|
||||||
|
grunt.initConfig({
|
||||||
|
connect: {
|
||||||
|
dev: {
|
||||||
|
options: {
|
||||||
|
port: 8680,
|
||||||
|
base: '.',
|
||||||
|
keepalive: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
options: {
|
||||||
|
port: 8681,
|
||||||
|
base: '.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mocha: {
|
||||||
|
all: {
|
||||||
|
options: {
|
||||||
|
urls: ['http://localhost:<%= connect.test.options.port %>/test/integration/index.html'],
|
||||||
|
run: false,
|
||||||
|
reporter: 'Spec'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
copy: {
|
||||||
|
npm: {
|
||||||
|
expand: true,
|
||||||
|
flatten: true,
|
||||||
|
cwd: 'node_modules/',
|
||||||
|
src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js'],
|
||||||
|
dest: 'test/integration/lib/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load the plugin(s)
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||||
|
grunt.loadNpmTasks('grunt-mocha');
|
||||||
|
|
||||||
|
// Test/Dev tasks
|
||||||
|
grunt.registerTask('dev', ['connect:dev']);
|
||||||
|
grunt.registerTask('test', ['copy', 'connect:test', 'mocha']);
|
||||||
|
|
||||||
|
};
|
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "openpgpjs",
|
||||||
|
"version": "0.1.0-dev",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"pretest": "make minify",
|
||||||
|
"test": "grunt test",
|
||||||
|
"start": "grunt dev"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "0.4.1",
|
||||||
|
"mocha": "1.13.0",
|
||||||
|
"phantomjs": "1.9.1-9",
|
||||||
|
"requirejs": "2.1.8",
|
||||||
|
"chai": "1.7.2",
|
||||||
|
"sinon": "1.7.3",
|
||||||
|
"phantomjs": "1.9.1-9",
|
||||||
|
"grunt-contrib-connect": "0.5.0",
|
||||||
|
"grunt-contrib-copy": "0.4.1",
|
||||||
|
"grunt-mocha": "0.4.1"
|
||||||
|
}
|
||||||
|
}
|
19
test/integration/index.html
Normal file
19
test/integration/index.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>JavaScript Unit Tests</title>
|
||||||
|
<link rel="stylesheet" href="lib/mocha.css" />
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mocha"></div>
|
||||||
|
|
||||||
|
<script src="lib/chai.js"></script>
|
||||||
|
<script src="lib/sinon.js"></script>
|
||||||
|
<script src="lib/mocha.js"></script>
|
||||||
|
|
||||||
|
<script data-main="main.js" src="lib/require.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
25
test/integration/main.js
Normal file
25
test/integration/main.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// config require.js
|
||||||
|
require.config({
|
||||||
|
baseUrl: './',
|
||||||
|
paths: {
|
||||||
|
openpgp: '../../resources/openpgp.min'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
openpgp: {
|
||||||
|
exports: 'window'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// start mocha tests
|
||||||
|
mocha.setup('bdd');
|
||||||
|
require(
|
||||||
|
[
|
||||||
|
'pgp-test'
|
||||||
|
], function() {
|
||||||
|
// require modules loaded -> run tests
|
||||||
|
mocha.run();
|
||||||
|
}
|
||||||
|
);
|
159
test/integration/pgp-test.js
Normal file
159
test/integration/pgp-test.js
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PGP = require('pgp'),
|
||||||
|
expect = chai.expect;
|
||||||
|
|
||||||
|
describe('PGP Crypto Api unit tests', function() {
|
||||||
|
var pgp,
|
||||||
|
user = 'test@t-online.de',
|
||||||
|
passphrase = 'asdf',
|
||||||
|
keySize = 512,
|
||||||
|
keyId = 'F6F60E9B42CDFF4C',
|
||||||
|
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
|
||||||
|
'Version: OpenPGP.js v.1.20131011\n' +
|
||||||
|
'Comment: http://openpgpjs.org\n' +
|
||||||
|
'\n' +
|
||||||
|
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\n' +
|
||||||
|
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\n' +
|
||||||
|
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\n' +
|
||||||
|
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\n' +
|
||||||
|
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\n' +
|
||||||
|
'=6XMW\n' +
|
||||||
|
'-----END PGP PUBLIC KEY BLOCK-----',
|
||||||
|
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
|
||||||
|
'Version: OpenPGP.js v.1.20131011\n' +
|
||||||
|
'Comment: http://openpgpjs.org\n' +
|
||||||
|
'\n' +
|
||||||
|
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\n' +
|
||||||
|
'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\n' +
|
||||||
|
'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\n' +
|
||||||
|
'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\n' +
|
||||||
|
'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\n' +
|
||||||
|
'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\n' +
|
||||||
|
'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\n' +
|
||||||
|
'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\n' +
|
||||||
|
'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\n' +
|
||||||
|
'IUNzVPLhrFIuKyBDTpLnC07Loce1\n' +
|
||||||
|
'=ULta\n' +
|
||||||
|
'-----END PGP PRIVATE KEY BLOCK-----';
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
pgp = new PGP();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {});
|
||||||
|
|
||||||
|
describe('Generate key pair', function() {
|
||||||
|
it('should fail', function(done) {
|
||||||
|
pgp.generateKeys({
|
||||||
|
emailAddress: 'test@t-onlinede',
|
||||||
|
keySize: keySize,
|
||||||
|
passphrase: passphrase
|
||||||
|
}, function(err, keys) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keys).to.not.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should fail', function(done) {
|
||||||
|
pgp.generateKeys({
|
||||||
|
emailAddress: 'testt-online.de',
|
||||||
|
keySize: keySize,
|
||||||
|
passphrase: passphrase
|
||||||
|
}, function(err, keys) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keys).to.not.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should work', function(done) {
|
||||||
|
pgp.generateKeys({
|
||||||
|
emailAddress: user,
|
||||||
|
keySize: keySize,
|
||||||
|
passphrase: passphrase
|
||||||
|
}, function(err, keys) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(keys.keyId).to.exist;
|
||||||
|
expect(keys.privateKeyArmored).to.exist;
|
||||||
|
expect(keys.publicKeyArmored).to.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Import/Export key pair', function() {
|
||||||
|
it('should fail', function(done) {
|
||||||
|
pgp.importKeys({
|
||||||
|
passphrase: 'asd',
|
||||||
|
privateKeyArmored: privkey,
|
||||||
|
publicKeyArmored: pubkey
|
||||||
|
}, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
|
||||||
|
pgp.exportKeys(function(err, keys) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
expect(keys).to.not.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should work', function(done) {
|
||||||
|
pgp.importKeys({
|
||||||
|
passphrase: passphrase,
|
||||||
|
privateKeyArmored: privkey,
|
||||||
|
publicKeyArmored: pubkey
|
||||||
|
}, function(err) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
|
||||||
|
pgp.exportKeys(function(err, keys) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(keys.keyId).to.equal(keyId);
|
||||||
|
expect(keys.privateKeyArmored).to.equal(privkey);
|
||||||
|
expect(keys.publicKeyArmored).to.equal(pubkey);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Encryption', function() {
|
||||||
|
var message = 'Hello, World!',
|
||||||
|
ciphertext;
|
||||||
|
|
||||||
|
beforeEach(function(done) {
|
||||||
|
pgp.importKeys({
|
||||||
|
passphrase: passphrase,
|
||||||
|
privateKeyArmored: privkey,
|
||||||
|
publicKeyArmored: pubkey
|
||||||
|
}, function(err) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Encrypt', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
pgp.encrypt(message, [pubkey], function(err, ct) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(ct).to.exist;
|
||||||
|
ciphertext = ct;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Decrypt', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
pgp.decrypt(ciphertext, pubkey, function(err, pt) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(pt).to.equal(message);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
173
test/integration/pgp.js
Normal file
173
test/integration/pgp.js
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/**
|
||||||
|
* High level crypto api that handles all calls to OpenPGP.js
|
||||||
|
*/
|
||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var openpgp = require('openpgp').openpgp,
|
||||||
|
util = require('openpgp').util;
|
||||||
|
|
||||||
|
var PGP = function() {
|
||||||
|
openpgp.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a key pair for the user
|
||||||
|
*/
|
||||||
|
PGP.prototype.generateKeys = function(options, callback) {
|
||||||
|
var keys, userId;
|
||||||
|
|
||||||
|
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize || typeof options.passphrase !== 'string') {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Crypto init failed. Not all options set!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate keypair (keytype 1=RSA)
|
||||||
|
try {
|
||||||
|
userId = 'Whiteout User <' + options.emailAddress + '>';
|
||||||
|
keys = openpgp.generate_key_pair(1, options.keySize, userId, options.passphrase);
|
||||||
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Keygeneration failed!',
|
||||||
|
err: e
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, {
|
||||||
|
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(),
|
||||||
|
privateKeyArmored: keys.privateKeyArmored,
|
||||||
|
publicKeyArmored: keys.publicKeyArmored
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import the user's key pair
|
||||||
|
*/
|
||||||
|
PGP.prototype.importKeys = function(options, callback) {
|
||||||
|
var publicKey, privateKey;
|
||||||
|
|
||||||
|
// check passphrase
|
||||||
|
if (typeof options.passphrase !== 'string' || !options.privateKeyArmored || !options.publicKeyArmored) {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Importing keys failed. Not all options set!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear any keypair already in the keychain
|
||||||
|
openpgp.keyring.init();
|
||||||
|
// unlock and import private key
|
||||||
|
if (!openpgp.keyring.importPrivateKey(options.privateKeyArmored, options.passphrase)) {
|
||||||
|
openpgp.keyring.init();
|
||||||
|
callback({
|
||||||
|
errMsg: 'Incorrect passphrase!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// import public key
|
||||||
|
openpgp.keyring.importPublicKey(options.publicKeyArmored);
|
||||||
|
|
||||||
|
// check if keys have the same id
|
||||||
|
privateKey = openpgp.keyring.exportPrivateKey(0);
|
||||||
|
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
||||||
|
if (!privateKey || !privateKey.armored || !publicKey || !publicKey.armored || privateKey.keyId !== publicKey.keyId) {
|
||||||
|
// reset keyring
|
||||||
|
openpgp.keyring.init();
|
||||||
|
callback({
|
||||||
|
errMsg: 'Key IDs dont match!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the user's key pair
|
||||||
|
*/
|
||||||
|
PGP.prototype.exportKeys = function(callback) {
|
||||||
|
var publicKey, privateKey;
|
||||||
|
|
||||||
|
privateKey = openpgp.keyring.exportPrivateKey(0);
|
||||||
|
if (privateKey && privateKey.keyId) {
|
||||||
|
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!privateKey || !privateKey.keyId || !privateKey.armored || !publicKey || !publicKey.armored) {
|
||||||
|
callback({
|
||||||
|
errMsg: 'Could not export keys!'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, {
|
||||||
|
keyId: util.hexstrdump(privateKey.keyId).toUpperCase(),
|
||||||
|
privateKeyArmored: privateKey.armored,
|
||||||
|
publicKeyArmored: publicKey.armored
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt and sign a pgp message for a list of receivers
|
||||||
|
*/
|
||||||
|
PGP.prototype.encrypt = function(plaintext, receiverKeys, callback) {
|
||||||
|
var ct, i,
|
||||||
|
privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
||||||
|
|
||||||
|
for (i = 0; i < receiverKeys.length; i++) {
|
||||||
|
receiverKeys[i] = openpgp.read_publicKey(receiverKeys[i])[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
ct = openpgp.write_signed_and_encrypted_message(privateKey, receiverKeys, plaintext);
|
||||||
|
|
||||||
|
callback(null, ct);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt and verify a pgp message for a single sender
|
||||||
|
*/
|
||||||
|
PGP.prototype.decrypt = function(ciphertext, senderKey, callback) {
|
||||||
|
var privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
||||||
|
senderKey = openpgp.read_publicKey(senderKey)[0];
|
||||||
|
|
||||||
|
var msg = openpgp.read_message(ciphertext)[0];
|
||||||
|
var keymat = null;
|
||||||
|
var sesskey = null;
|
||||||
|
|
||||||
|
// Find the private (sub)key for the session key of the message
|
||||||
|
for (var i = 0; i < msg.sessionKeys.length; i++) {
|
||||||
|
if (privateKey.privateKeyPacket.publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
||||||
|
keymat = {
|
||||||
|
key: privateKey,
|
||||||
|
keymaterial: privateKey.privateKeyPacket
|
||||||
|
};
|
||||||
|
sesskey = msg.sessionKeys[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (var j = 0; j < privateKey.subKeys.length; j++) {
|
||||||
|
if (privateKey.subKeys[j].publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
||||||
|
keymat = {
|
||||||
|
key: privateKey,
|
||||||
|
keymaterial: privateKey.subKeys[j]
|
||||||
|
};
|
||||||
|
sesskey = msg.sessionKeys[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keymat !== null) {
|
||||||
|
var decrypted = msg.decryptAndVerifySignature(keymat, sesskey, senderKey);
|
||||||
|
callback(null, decrypted.text);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
callback({
|
||||||
|
errMsg: 'No private key found!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return PGP;
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user