WIP on crypto wrapper providers for AES, TripleDES, Rabbit, 3 tests failing
This commit is contained in:
parent
807f93798c
commit
58f57cca19
|
@ -0,0 +1,125 @@
|
|||
define(function(require) {
|
||||
var FILE_SYSTEM_NAME = require('src/constants').FILE_SYSTEM_NAME;
|
||||
|
||||
// AES encryption, see http://code.google.com/p/crypto-js/#AES
|
||||
require("crypto-js/rollups/aes");
|
||||
// DES, Triple DES, see http://code.google.com/p/crypto-js/#DES,_Triple_DES
|
||||
require("crypto-js/rollups/tripledes");
|
||||
// Rabbit, see http://code.google.com/p/crypto-js/#Rabbi
|
||||
require("crypto-js/rollups/rabbit");
|
||||
|
||||
function CryptoWrappedContext(context, encrypt, decrypt) {
|
||||
this.context = context;
|
||||
this.encrypt = encrypt;
|
||||
this.decrypt = decrypt;
|
||||
}
|
||||
CryptoWrappedContext.prototype.clear = function(callback) {
|
||||
this.context.clear(callback);
|
||||
};
|
||||
CryptoWrappedContext.prototype.get = function(key, callback) {
|
||||
var that = this;
|
||||
var encryptedKey = this.encrypt(key);
|
||||
this.context.get(encryptedKey, function(err, value) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if(value) {
|
||||
value = that.decrypt(value);
|
||||
}
|
||||
callback(null, value);
|
||||
});
|
||||
};
|
||||
CryptoWrappedContext.prototype.put = function(key, value, callback) {
|
||||
var encryptedKey = this.encrypt(key);
|
||||
var encryptedValue = this.encrypt(value);
|
||||
this.context.put(encryptedKey, encryptedValue, callback);
|
||||
};
|
||||
CryptoWrappedContext.prototype.delete = function(key, callback) {
|
||||
var encryptedKey = this.encrypt(key);
|
||||
this.context.delete(encryptedKey, callback);
|
||||
};
|
||||
|
||||
// Custom formatting for encryption objects <-> strings
|
||||
var formatter = {
|
||||
stringify: function(cipherParams) {
|
||||
// create json object with ciphertext
|
||||
var jsonObj = {
|
||||
ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)
|
||||
};
|
||||
|
||||
// cache iv and salt
|
||||
if (cipherParams.iv) {
|
||||
jsonObj.iv = cipherParams.iv.toString();
|
||||
}
|
||||
if (cipherParams.salt) {
|
||||
jsonObj.s = cipherParams.salt.toString();
|
||||
}
|
||||
|
||||
// stringify json object
|
||||
return JSON.stringify(jsonObj);
|
||||
},
|
||||
|
||||
parse: function(jsonString) {
|
||||
// parse json string
|
||||
var jsonObj;
|
||||
try {
|
||||
jsonObj = JSON.parse(jsonString);
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
// extract ciphertext from json object, and create cipher params object
|
||||
var cipherParams = CryptoJS.lib.CipherParams.create({
|
||||
ciphertext: CryptoJS.enc.Base64.parse(jsonObj.ct)
|
||||
});
|
||||
|
||||
// extract iv and salt
|
||||
if (jsonObj.iv) {
|
||||
cipherParams.iv = CryptoJS.enc.Hex.parse(jsonObj.iv);
|
||||
}
|
||||
if (jsonObj.s) {
|
||||
cipherParams.salt = CryptoJS.enc.Hex.parse(jsonObj.s);
|
||||
}
|
||||
|
||||
return cipherParams;
|
||||
}
|
||||
};
|
||||
|
||||
function buildCryptoWrapper(encryptionType) {
|
||||
// It is up to the app using this wrapper how the passphrase is acquired, probably by
|
||||
// prompting the user to enter it when the file system is being opened.
|
||||
function CryptoWrappedProvider(passphrase, provider) {
|
||||
this.provider = provider;
|
||||
this.encrypt = function(plain) {
|
||||
console.log('encrypt', plain, CryptoJS[encryptionType].encrypt(plain, passphrase).toString());
|
||||
return CryptoJS[encryptionType].encrypt(plain, passphrase, {format: formatter}).toString();
|
||||
};
|
||||
this.decrypt = function(encrypted) {
|
||||
console.log('decrypt', encrypted, CryptoJS[encryptionType].decrypt(encrypted, passphrase).toString());
|
||||
return CryptoJS[encryptionType].decrypt(encrypted, passphrase, {format: formatter}).toString();
|
||||
};
|
||||
}
|
||||
CryptoWrappedProvider.isSupported = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
CryptoWrappedProvider.prototype.open = function(callback) {
|
||||
this.provider.open(callback);
|
||||
};
|
||||
CryptoWrappedProvider.prototype.getReadOnlyContext = function() {
|
||||
return new CryptoWrappedContext(this.provider.getReadOnlyContext(), this.encrypt, this.decrypt);
|
||||
};
|
||||
CryptoWrappedProvider.prototype.getReadWriteContext = function() {
|
||||
return new CryptoWrappedContext(this.provider.getReadWriteContext(), this.encrypt, this.decrypt);
|
||||
};
|
||||
|
||||
return CryptoWrappedProvider;
|
||||
}
|
||||
|
||||
return {
|
||||
AESWrapper: buildCryptoWrapper('AES'),
|
||||
TripleDESWrapper: buildCryptoWrapper('TripleDES'),
|
||||
RabbitWrapper: buildCryptoWrapper('Rabbit')
|
||||
};
|
||||
});
|
|
@ -3,12 +3,32 @@ define(function(require) {
|
|||
var IndexedDB = require('src/providers/indexeddb');
|
||||
var WebSQL = require('src/providers/websql');
|
||||
var Memory = require('src/providers/memory');
|
||||
var CryptoWrappers = require('src/providers/crypto-wrappers');
|
||||
|
||||
return {
|
||||
IndexedDB: IndexedDB,
|
||||
WebSQL: WebSQL,
|
||||
Memory: Memory,
|
||||
|
||||
/**
|
||||
* Wrappers for composing various types of providers
|
||||
*/
|
||||
|
||||
// Encryption Wrappers
|
||||
AESWrapper: CryptoWrappers.AESWrapper,
|
||||
TripleDESWrapper: CryptoWrappers.TripleDESWrapper,
|
||||
RabbitWrapper: CryptoWrappers.RabbitWrapper,
|
||||
// Convenience encryption wrapper
|
||||
EncryptionWrapper: CryptoWrappers.AESWrapper,
|
||||
|
||||
|
||||
/**
|
||||
* Convenience Provider references
|
||||
*/
|
||||
|
||||
// The default provider to use when none is specified
|
||||
Default: IndexedDB,
|
||||
|
||||
// The Fallback provider does automatic fallback checks
|
||||
Fallback: (function() {
|
||||
if(IndexedDB.isSupported()) {
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
define(["IDBFS"], function(IDBFS) {
|
||||
|
||||
// We reuse the same set of tests for all crypto providers.
|
||||
// buildTestsFor() creates a set of tests bound to a crypto
|
||||
// provider, and uses a Memory() provider internally.
|
||||
|
||||
function buildTestsFor(wrapperName) {
|
||||
var passphrase = '' + Date.now();
|
||||
|
||||
function createProvider() {
|
||||
var memoryProvider = new IDBFS.FileSystem.providers.Memory();
|
||||
return new IDBFS.FileSystem.providers[wrapperName](passphrase, memoryProvider);
|
||||
}
|
||||
|
||||
describe("IDBFS.FileSystem.providers" + wrapperName, function() {
|
||||
it("is supported -- if it isn't, none of these tests can run.", function() {
|
||||
expect(IDBFS.FileSystem.providers[wrapperName].isSupported()).toEqual(true);
|
||||
});
|
||||
|
||||
it("has open, getReadOnlyContext, and getReadWriteContext instance methods", function() {
|
||||
var indexedDBProvider = createProvider();
|
||||
expect(typeof indexedDBProvider.open).toEqual('function');
|
||||
expect(typeof indexedDBProvider.getReadOnlyContext).toEqual('function');
|
||||
expect(typeof indexedDBProvider.getReadWriteContext).toEqual('function');
|
||||
});
|
||||
|
||||
describe("open an Memory provider", function() {
|
||||
it("should open a new Memory database", function() {
|
||||
var complete = false;
|
||||
var _error, _result;
|
||||
|
||||
var provider = createProvider();
|
||||
provider.open(function(err, firstAccess) {
|
||||
_error = err;
|
||||
_result = firstAccess;
|
||||
complete = true;
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
return complete;
|
||||
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||
|
||||
runs(function() {
|
||||
expect(_error).toEqual(null);
|
||||
expect(_result).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Read/Write operations on an Memory provider", function() {
|
||||
it("should allow put() and get()", function() {
|
||||
var complete = false;
|
||||
var _error, _result;
|
||||
|
||||
var provider = createProvider();
|
||||
provider.open(function(err, firstAccess) {
|
||||
_error = err;
|
||||
|
||||
var context = provider.getReadWriteContext();
|
||||
context.put("key", "value", function(err, result) {
|
||||
_error = _error || err;
|
||||
context.get("key", function(err, result) {
|
||||
_error = _error || err;
|
||||
_result = result;
|
||||
|
||||
complete = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
return complete;
|
||||
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||
|
||||
runs(function() {
|
||||
expect(_error).toEqual(null);
|
||||
expect(_result).toEqual("value");
|
||||
});
|
||||
});
|
||||
|
||||
it("should allow delete()", function() {
|
||||
var complete = false;
|
||||
var _error, _result;
|
||||
|
||||
var provider = createProvider();
|
||||
provider.open(function(err, firstAccess) {
|
||||
_error = err;
|
||||
|
||||
var context = provider.getReadWriteContext();
|
||||
context.put("key", "value", function(err, result) {
|
||||
_error = _error || err;
|
||||
context.delete("key", function(err, result) {
|
||||
_error = _error || err;
|
||||
context.get("key", function(err, result) {
|
||||
_error = _error || err;
|
||||
_result = result;
|
||||
|
||||
complete = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
return complete;
|
||||
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||
|
||||
runs(function() {
|
||||
expect(_error).toEqual(null);
|
||||
expect(_result).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
it("should allow clear()", function() {
|
||||
var complete = false;
|
||||
var _error, _result1, _result2;
|
||||
|
||||
var provider = createProvider();
|
||||
provider.open(function(err, firstAccess) {
|
||||
_error = err;
|
||||
|
||||
var context = provider.getReadWriteContext();
|
||||
context.put("key1", "value1", function(err, result) {
|
||||
_error = _error || err;
|
||||
context.put("key2", "value2", function(err, result) {
|
||||
_error = _error || err;
|
||||
|
||||
context.clear(function(err) {
|
||||
_error = _error || err;
|
||||
|
||||
context.get("key1", function(err, result) {
|
||||
_error = _error || err;
|
||||
_result1 = result;
|
||||
|
||||
context.get("key2", function(err, result) {
|
||||
_error = _error || err;
|
||||
_result2 = result;
|
||||
|
||||
complete = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
return complete;
|
||||
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||
|
||||
runs(function() {
|
||||
expect(_error).toEqual(null);
|
||||
expect(_result1).toEqual(null);
|
||||
expect(_result2).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail when trying to write on ReadOnlyContext", function() {
|
||||
var complete = false;
|
||||
var _error, _result;
|
||||
|
||||
var provider = createProvider();
|
||||
provider.open(function(err, firstAccess) {
|
||||
_error = err;
|
||||
|
||||
var context = provider.getReadOnlyContext();
|
||||
context.put("key1", "value1", function(err, result) {
|
||||
_error = _error || err;
|
||||
_result = result;
|
||||
|
||||
complete = true;
|
||||
});
|
||||
});
|
||||
|
||||
waitsFor(function() {
|
||||
return complete;
|
||||
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||
|
||||
runs(function() {
|
||||
expect(_error).toBeDefined();
|
||||
expect(_result).toEqual(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
buildTestsFor('AESWrapper');
|
||||
buildTestsFor('TripleDESWrapper');
|
||||
buildTestsFor('RabbitWrapper');
|
||||
|
||||
});
|
|
@ -16,6 +16,18 @@ define(["IDBFS"], function(IDBFS) {
|
|||
expect(typeof IDBFS.FileSystem.providers.Memory).toEqual('function');
|
||||
});
|
||||
|
||||
it("has an AESWrapper constructor", function() {
|
||||
expect(typeof IDBFS.FileSystem.providers.AESWrapper).toEqual('function');
|
||||
});
|
||||
|
||||
it("has a TripleDESWrapper constructor", function() {
|
||||
expect(typeof IDBFS.FileSystem.providers.TripleDESWrapper).toEqual('function');
|
||||
});
|
||||
|
||||
it("has a RabbitWrapper constructor", function() {
|
||||
expect(typeof IDBFS.FileSystem.providers.RabbitWrapper).toEqual('function');
|
||||
});
|
||||
|
||||
it("has a Default constructor", function() {
|
||||
expect(typeof IDBFS.FileSystem.providers.Default).toEqual('function');
|
||||
});
|
||||
|
|
|
@ -33,6 +33,7 @@ define([
|
|||
"spec/providers/providers.memory.spec",
|
||||
"spec/providers/providers.indexeddb.spec",
|
||||
"spec/providers/providers.websql.spec",
|
||||
"spec/providers/providers.crypto.spec",
|
||||
|
||||
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||
"spec/node-js/simple/test-fs-mkdir",
|
||||
|
|
Loading…
Reference in New Issue