1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

Began adding browser-native encryptor module

Added new Qunit build process that will browserify the contents of `test/integration/lib` into the QUnit browser, allowing much more modular testing, including unit testing of our modules in our target browsers.

Made a basic unit test file of this form for the new encryptor module, which fails miserably because I've only just begun to work with it.

I've started with this blog post as a starting point, and will be adjusting it to our needs from there:
http://qnimate.com/passphrase-based-encryption-using-web-cryptography-api/
This commit is contained in:
Dan Finlay 2016-10-12 20:03:14 -07:00
parent cd2c00a318
commit cce8d9e360
8 changed files with 201 additions and 3 deletions

View File

@ -90,6 +90,10 @@ You can also test with a continuously watching process, via `npm run watch`.
You can run the linter by itself with `gulp lint`. You can run the linter by itself with `gulp lint`.
#### Writing Browser Tests
To write tests that will be run in the browser using QUnit, add your test files to `test/integration/lib`.
### Deploying the UI ### Deploying the UI
You must be authorized already on the MetaMask plugin. You must be authorized already on the MetaMask plugin.

View File

@ -0,0 +1,51 @@
var vector = global.crypto.getRandomValues(new Uint8Array(16))
var key = null
module.exports = {
encrypt,
decrypt,
convertArrayBufferViewtoString,
keyFromPassword,
}
// Takes a Pojo, returns encrypted text.
function encrypt (password, dataObj) {
var data = JSON.stringify(dataObj)
global.crypto.subtle.encrypt({name: 'AES-CBC', iv: vector}, key, convertStringToArrayBufferView(data)).then(function(result){
const encryptedData = new Uint8Array(result)
return encryptedData
},
function(e){
console.log(e.message)
})
}
// Takes encrypted text, returns the restored Pojo.
function decrypt (password, text) {
}
function convertStringToArrayBufferView (str) {
var bytes = new Uint8Array(str.length)
for (var i = 0; i < str.length; i++) {
bytes[i] = str.charCodeAt(i)
}
return bytes
}
function convertArrayBufferViewtoString (buffer) {
var str = ''
for (var i = 0; i < buffer.byteLength; i++) {
str += String.fromCharCode(buffer[i])
}
return str
}
function keyFromPassword (password) {
global.crypto.subtle.digest({name: 'SHA-256'}, convertStringToArrayBufferView(password)).then(function(result){
return global.crypto.subtle.importKey('raw', result, {name: 'AES-CBC'}, false, ['encrypt', 'decrypt'])
})
}

View File

@ -8,6 +8,7 @@
"lint": "gulp lint", "lint": "gulp lint",
"dev": "gulp dev", "dev": "gulp dev",
"dist": "gulp dist", "dist": "gulp dist",
"buildCiUnits": "node test/integration/index.js",
"test": "npm run fastTest && npm run ci && npm run lint", "test": "npm run fastTest && npm run ci && npm run lint",
"fastTest": "mocha --require test/helper.js --compilers js:babel-register --recursive \"test/unit/**/*.js\"", "fastTest": "mocha --require test/helper.js --compilers js:babel-register --recursive \"test/unit/**/*.js\"",
"watch": "mocha watch --compilers js:babel-register --recursive \"test/unit/**/*.js\"", "watch": "mocha watch --compilers js:babel-register --recursive \"test/unit/**/*.js\"",
@ -15,7 +16,7 @@
"mock": "beefy mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "mock": "beefy mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"buildMock": "browserify ./mock-dev.js -o ./development/bundle.js", "buildMock": "browserify ./mock-dev.js -o ./development/bundle.js",
"testem": "npm run buildMock && testem", "testem": "npm run buildMock && testem",
"ci": "npm run buildMock && testem ci -P 2", "ci": "npm run buildMock && npm run buildCiUnits && testem ci -P 2",
"announce": "node development/announcer.js" "announce": "node development/announcer.js"
}, },
"browserify": { "browserify": {

103
test/integration/bundle.js Normal file
View File

@ -0,0 +1,103 @@
window.QUnit = QUnit; (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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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){
(function (global){
"use strict";
var vector = global.crypto.getRandomValues(new Uint8Array(16));
module.exports = {
encrypt: encrypt,
decrypt: decrypt
};
// Takes a Pojo, returns encrypted text.
function encrypt(password, dataObj) {
var data = JSON.stringify(dataObj);
global.crypto.subtle.encrypt({ name: "AES-CBC", iv: vector }, key, convertStringToArrayBufferView(data)).then(function (result) {
var encryptedData = new Uint8Array(result);
return encryptedData;
}, function (e) {
console.log(e.message);
});
}
// Takes encrypted text, returns the restored Pojo.
function decrypt(password, text) {}
function convertStringToArrayBufferView(str) {
var bytes = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) {
bytes[i] = str.charCodeAt(i);
}
return bytes;
}
function convertArrayBufferViewtoString(buffer) {
var str = "";
for (var i = 0; i < buffer.byteLength; i++) {
str += String.fromCharCode(buffer[i]);
}
return str;
}
var password = "password";
var key = null;
function keyFromPassword(password) {
global.crypto.subtle.digest({ name: "SHA-256" }, convertStringToArrayBufferView(password)).then(function (result) {
return global.crypto.subtle.importKey("raw", result, { name: "AES-CBC" }, false, ["encrypt", "decrypt"]);
});
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],2:[function(require,module,exports){
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
var encryptor = require('../../../app/scripts/lib/encryptor');
QUnit.test('encryptor', function (assert) {
var password, data, encrypted;
password = 'a sample passw0rd';
data = { foo: 'data to encrypt' };
encryptor.encrypt(password, data).then(function (result) {
assert.equal(typeof result === 'undefined' ? 'undefined' : _typeof(result), 'string', 'returns a string');
}).catch(function (reason) {
assert.ifError(reason, 'threw an error');
});
});
},{"../../../app/scripts/lib/encryptor":1}],3:[function(require,module,exports){
'use strict';
QUnit.test('agree to terms', function (assert) {
var done = assert.async();
// Select the mock app root
var app = $('iframe').contents().find('#app-content .mock-app-root');
app.find('.markdown').prop('scrollTop', 100000000);
wait().then(function () {
app.find('button').click();
}).then(function () {
return wait();
}).then(function () {
var title = app.find('h1').text();
assert.equal(title, 'MetaMask', 'title screen');
var buttons = app.find('button');
assert.equal(buttons.length, 1, 'one button: create new vault');
done();
});
// Wait for view to transition:
});
},{}]},{},[2,3]);

View File

@ -12,7 +12,7 @@
<script src="https://code.jquery.com/qunit/qunit-2.0.0.js"></script> <script src="https://code.jquery.com/qunit/qunit-2.0.0.js"></script>
<script src="./jquery-3.1.0.min.js"></script> <script src="./jquery-3.1.0.min.js"></script>
<script src="helpers.js"></script> <script src="helpers.js"></script>
<script src="tests.js"></script> <script src="bundle.js"></script>
<script src="/testem.js"></script> <script src="/testem.js"></script>
<iframe src="/development/index.html" height="500px" width="360px"> <iframe src="/development/index.html" height="500px" width="360px">

21
test/integration/index.js Normal file
View File

@ -0,0 +1,21 @@
var fs = require('fs')
var path = require('path')
var browserify = require('browserify');
var tests = fs.readdirSync(path.join(__dirname, 'lib'))
var bundlePath = path.join(__dirname, 'bundle.js')
var b = browserify();
// Remove old bundle
try {
fs.unlinkSync(bundlePath)
} catch (e) {}
var writeStream = fs.createWriteStream(bundlePath)
tests.forEach(function(fileName) {
b.add(path.join(__dirname, 'lib', fileName))
})
b.bundle().pipe(writeStream);

View File

@ -0,0 +1,17 @@
var encryptor = require('../../../app/scripts/lib/encryptor')
QUnit.test('encryptor', function(assert) {
var password, data, encrypted
password = 'a sample passw0rd'
data = { foo: 'data to encrypt' }
encryptor.encrypt(password, data)
.then(function(result) {
assert.equal(typeof result, 'string', 'returns a string')
})
.catch(function(reason) {
assert.ifError(reason, 'threw an error')
})
})

View File

@ -15,10 +15,11 @@ QUnit.test('agree to terms', function (assert) {
assert.equal(title, 'MetaMask', 'title screen') assert.equal(title, 'MetaMask', 'title screen')
var buttons = app.find('button') var buttons = app.find('button')
assert.equal(buttons.length, 2, 'two buttons: create and restore') assert.equal(buttons.length, 1, 'one button: create new vault')
done() done()
}) })
// Wait for view to transition: // Wait for view to transition:
}) })