finished frontend tests

This commit is contained in:
Abhinav Adduri 2017-07-12 16:23:55 -07:00
parent b411447ebb
commit 00462947e3
5 changed files with 201 additions and 66 deletions

View File

@ -1,2 +1,3 @@
public/bundle.js public/bundle.js
public/webcrypto-shim.js public/webcrypto-shim.js
test/frontend/bundle.js

View File

@ -0,0 +1,2 @@
env:
browser: true

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@ window.FakeFile = FakeFile;
window.FileSender = require('../../frontend/src/fileSender'); window.FileSender = require('../../frontend/src/fileSender');
window.FileReceiver = require('../../frontend/src/fileReceiver'); window.FileReceiver = require('../../frontend/src/fileReceiver');
window.sinon = require('sinon'); window.sinon = require('sinon');
window.server = window.sinon.fakeServer.create();
window.assert = require('assert'); window.assert = require('assert');
const utils = require('../../frontend/src/utils'); const utils = require('../../frontend/src/utils');
window.hexToArray = utils.hexToArray; window.hexToArray = utils.hexToArray;

View File

@ -1,27 +1,26 @@
const FileSender = window.FileSender; const FileSender = window.FileSender;
const FileReceiver = window.FileReceiver;
const FakeFile = window.FakeFile; const FakeFile = window.FakeFile;
const stubXML = window.stubXML;
const assert = window.assert; const assert = window.assert;
const server = window.server;
const hexToArray = window.hexToArray;
const arrayToHex = window.arrayToHex;
const sinon = window.sinon;
let file; let file;
let encryptedIV; let encryptedIV;
let fileHash; let fileHash;
let secretKey; let secretKey;
let blobReplacement; let originalBlob;
describe('File Sender', function() { describe('File Sender', function() {
let xhr;
let server;
before(function() { before(function() {
xhr = sinon.useFakeXMLHttpRequest();
server = sinon.fakeServer.create();
server.respondImmediately = true; server.respondImmediately = true;
server.respondWith( server.respondWith(
'POST', 'POST',
'/upload', '/upload',
function(request) { function(request) {
let reader = new FileReader(); const reader = new FileReader();
reader.readAsArrayBuffer(request.requestBody.get('data')); reader.readAsArrayBuffer(request.requestBody.get('data'));
reader.onload = function(event) { reader.onload = function(event) {
@ -29,7 +28,6 @@ describe('File Sender', function() {
} }
const responseObj = JSON.parse(request.requestHeaders['X-File-Metadata']); const responseObj = JSON.parse(request.requestHeaders['X-File-Metadata']);
request.respond( request.respond(
200, 200,
{'Content-Type': 'application/json'}, {'Content-Type': 'application/json'},
@ -42,75 +40,81 @@ describe('File Sender', function() {
}) })
it('Should get a loading event emission', function() { it('Should get a loading event emission', function() {
let file = new FakeFile('hello_world.txt', ['This is some data.']) const file = new FakeFile('hello_world.txt', ['This is some data.'])
let fs = new FileSender(file); const fs = new FileSender(file);
let testLoading = true; let testLoading = true;
fs.on('loading', isStillLoading => { fs.on('loading', isStillLoading => {
assert(!(!testLoading && isStillLoading)) assert(!(!testLoading && isStillLoading));
testLoading = isStillLoading testLoading = isStillLoading;
}) })
return fs.upload() return fs.upload()
.then(info => { .then(info => {
assert(!testLoading) assert(info);
assert(!testLoading);
}) })
.catch(err => { .catch(err => {
console.log(err, err.stack);
assert.fail(); assert.fail();
}); });
}) })
it('Should get a hashing event emission', function() { it('Should get a hashing event emission', function() {
let file = new FakeFile('hello_world.txt', ['This is some data.']) const file = new FakeFile('hello_world.txt', ['This is some data.'])
blobReplacement = file; const fs = new FileSender(file);
let fs = new FileSender(file);
let testHashing = true; let testHashing = true;
fs.on('hashing', isStillHashing => { fs.on('hashing', isStillHashing => {
assert(!(!testHashing && isStillHashing)) assert(!(!testHashing && isStillHashing));
testHashing = isStillHashing testHashing = isStillHashing;
}) })
return fs.upload() return fs.upload()
.then(info => { .then(info => {
assert(!testHashing) assert(info);
assert(!testHashing);
}) })
.catch(err => { .catch(err => {
console.log(err, err.stack);
assert.fail(); assert.fail();
}); });
}) })
it('Should get a encrypting event emission', function() { it('Should get a encrypting event emission', function() {
let file = new FakeFile('hello_world.txt', ['This is some data.']) const file = new FakeFile('hello_world.txt', ['This is some data.'])
let fs = new FileSender(file); const fs = new FileSender(file);
let testEncrypting = true; let testEncrypting = true;
fs.on('encrypting', isStillEncrypting => { fs.on('encrypting', isStillEncrypting => {
assert(!(!testEncrypting && isStillEncrypting)) assert(!(!testEncrypting && isStillEncrypting));
testEncrypting = isStillEncrypting testEncrypting = isStillEncrypting;
}) })
return fs.upload() return fs.upload()
.then(info => { .then(info => {
assert(!testEncrypting) assert(info);
assert(!testEncrypting);
}) })
.catch(err => { .catch(err => {
console.log(err, err.stack);
assert.fail(); assert.fail();
}); });
}) })
it('Should encrypt a file properly', function(done) { it('Should encrypt a file properly', function(done) {
let newFile = new FakeFile('hello_world.txt', ['This is some data.']) const newFile = new FakeFile('hello_world.txt', ['This is some data.'])
let fs = new FileSender(newFile); const fs = new FileSender(newFile);
fs.upload().then(info => { fs.upload().then(info => {
let key = info.secretKey; const key = info.secretKey;
secretKey = info.secretKey; secretKey = info.secretKey;
let IV = info.fileId; const IV = info.fileId;
encryptedIV = info.fileId; encryptedIV = info.fileId;
let readRaw = new FileReader; const readRaw = new FileReader;
readRaw.onload = function(event) { readRaw.onload = function(event) {
let rawArray = new Uint8Array(this.result); const rawArray = new Uint8Array(this.result);
originalBlob = rawArray;
window.crypto.subtle.digest('SHA-256', rawArray).then(hash => { window.crypto.subtle.digest('SHA-256', rawArray).then(hash => {
fileHash = hash; fileHash = hash;
@ -155,57 +159,183 @@ describe('File Sender', function() {
}); });
describe('File Receiver', function(done) { describe('File Receiver', function() {
class FakeXHR {
constructor() {
this.response = file;
this.status = 200;
}
static setup() {
FakeXHR.prototype.open = sinon.spy();
FakeXHR.prototype.send = function () {
this.onload();
}
FakeXHR.prototype.originalXHR = window.XMLHttpRequest;
FakeXHR.prototype.getResponseHeader = function () {
return JSON.stringify({
aad: arrayToHex(new Uint8Array(fileHash)),
filename: 'hello_world.txt',
id: encryptedIV
})
}
window.XMLHttpRequest = FakeXHR;
}
static restore() {
// originalXHR is a sinon FakeXMLHttpRequest, since
// fakeServer.create() is called in frontend.bundle.js
window.XMLHttpRequest.prototype.originalXHR.restore();
}
}
const cb = function(done) { const cb = function(done) {
if (file === undefined || if (file === undefined ||
encryptedIV === undefined || encryptedIV === undefined ||
fileHash === undefined || fileHash === undefined ||
secretKey === undefined) { secretKey === undefined) {
setTimeout(cb, 1000); assert.fail('Please run file sending tests before trying to receive the files.');
return; done();
} }
let xhr; FakeXHR.setup();
let server;
xhr = sinon.useFakeXMLHttpRequest();
server = sinon.fakeServer.create();
server.respondImmediately = true;
// xhr.prototype.response = file;
server.respondWith(
'GET',
'/assets' + location.pathname.slice(0, -1),
function(request) {
request.respond(
200,
{
'Content-Disposition': 'attachment; filename=hello_world.txt',
'Content-Type': 'application/octet-stream',
'Content-Length': file.byteLength,
'X-File-Metadata': JSON.stringify({
aad: arrayToHex(new Uint8Array(fileHash)),
filename: 'hello_world.txt',
id: encryptedIV
})
},
String.fromCharCode.apply(String, new Uint8Array(file))
)
}
)
done(); done();
} }
before(cb) before(cb)
after(function() {
FakeXHR.restore();
})
it('Should decrypt properly', function() { it('Should decrypt properly', function() {
let fr = new FileReceiver(); const fr = new FileReceiver();
location.hash = secretKey; location.hash = secretKey;
return fr.download().then(([decrypted, name]) => { return fr.download().then(([decrypted, name]) => {
console.log('here') assert(name);
assert(new Uint8Array(decrypted).toString() ===
new Uint8Array(originalBlob).toString())
}).catch(err => { }).catch(err => {
console.log(err, err.stack) console.log(err, err.stack);
assert.fail();
}) })
}) })
it('Should emit decrypting events', function() {
const fr = new FileReceiver();
location.hash = secretKey;
let testDecrypting = true;
fr.on('decrypting', isStillDecrypting => {
assert(!(!testDecrypting && isStillDecrypting));
testDecrypting = isStillDecrypting;
});
return fr.download().then(([decrypted, name]) => {
assert(decrypted);
assert(name);
assert(!testDecrypting);
}).catch(err => {
console.log(err, err.stack);
assert.fail();
})
})
it('Should emit hashing events', function() {
const fr = new FileReceiver();
location.hash = secretKey;
let testHashing = true;
fr.on('hashing', isStillHashing => {
assert(!(!testHashing && isStillHashing));
testHashing = isStillHashing;
});
return fr.download().then(([decrypted, name]) => {
assert(decrypted);
assert(name);
assert(!testHashing);
}).catch(err => {
assert.fail();
})
})
it('Should catch tampered checksums', function(done) {
// use the secret key and file hash of the previous file to encrypt,
// which has a different hash than this one (different strings)
const newFile = new FakeFile('hello_world.txt',
['This is some data, with a changed hash.'])
const readRaw = new FileReader();
readRaw.onload = function(event) {
const plaintext = new Uint8Array(this.result);
window.crypto.subtle.importKey(
'jwk',
{
kty: 'oct',
k: secretKey,
alg: 'A128GCM',
ext: true
},
{
name: 'AES-GCM'
},
true,
['encrypt', 'decrypt']
)
.then(key => {
return window.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: hexToArray(encryptedIV),
additionalData: fileHash,
tagLength: 128
},
key,
plaintext
)
})
.then(encrypted => {
file = encrypted;
const fr = new FileReceiver();
location.hash = secretKey;
fr.download().then(() => {
assert.fail();
done();
}).catch(err => {
assert(1);
done();
})
})
}
readRaw.readAsArrayBuffer(newFile);
})
it('Should not decrypt with an incorrect checksum', function() {
FakeXHR.prototype.getResponseHeader = function () {
return JSON.stringify({
aad: 'some_bad_hashz',
filename: 'hello_world.txt',
id: encryptedIV
})
}
const fr = new FileReceiver();
location.hash = secretKey;
return fr.download().then(([decrypted, name]) => {
assert(decrypted);
assert(name);
assert.fail();
}).catch(err => {
assert(1);
})
})
}) })