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 IndexedDB = require('src/providers/indexeddb');
|
||||||
var WebSQL = require('src/providers/websql');
|
var WebSQL = require('src/providers/websql');
|
||||||
var Memory = require('src/providers/memory');
|
var Memory = require('src/providers/memory');
|
||||||
|
var CryptoWrappers = require('src/providers/crypto-wrappers');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
IndexedDB: IndexedDB,
|
IndexedDB: IndexedDB,
|
||||||
WebSQL: WebSQL,
|
WebSQL: WebSQL,
|
||||||
Memory: Memory,
|
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,
|
Default: IndexedDB,
|
||||||
|
|
||||||
// The Fallback provider does automatic fallback checks
|
// The Fallback provider does automatic fallback checks
|
||||||
Fallback: (function() {
|
Fallback: (function() {
|
||||||
if(IndexedDB.isSupported()) {
|
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');
|
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() {
|
it("has a Default constructor", function() {
|
||||||
expect(typeof IDBFS.FileSystem.providers.Default).toEqual('function');
|
expect(typeof IDBFS.FileSystem.providers.Default).toEqual('function');
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,6 +33,7 @@ define([
|
||||||
"spec/providers/providers.memory.spec",
|
"spec/providers/providers.memory.spec",
|
||||||
"spec/providers/providers.indexeddb.spec",
|
"spec/providers/providers.indexeddb.spec",
|
||||||
"spec/providers/providers.websql.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)
|
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
|
||||||
"spec/node-js/simple/test-fs-mkdir",
|
"spec/node-js/simple/test-fs-mkdir",
|
||||||
|
|
Loading…
Reference in New Issue