1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 02:42:17 -05:00

Implement setDeviceName and generateDeviceSecret

This commit is contained in:
Tankred Hase 2014-06-05 17:14:46 +02:00
parent 4880c162f8
commit e720753779
2 changed files with 146 additions and 16 deletions

View File

@ -5,7 +5,13 @@
define(function(require) { define(function(require) {
'use strict'; 'use strict';
var _ = require('underscore'); var _ = require('underscore'),
util = require('js/crypto/util');
var DB_PUBLICKEY = 'publickey',
DB_PRIVATEKEY = 'privatekey',
DB_DEVICENAME = 'devicename',
DB_DEVICEKEY = 'devicekey';
var KeychainDAO = function(localDbDao, publicKeyDao, privateKeyDao, crypto) { var KeychainDAO = function(localDbDao, publicKeyDao, privateKeyDao, crypto) {
this._localDbDao = localDbDao; this._localDbDao = localDbDao;
@ -176,7 +182,7 @@ define(function(require) {
var self = this; var self = this;
// search local keyring for public key // search local keyring for public key
self._localDbDao.list('publickey', 0, null, function(err, allPubkeys) { self._localDbDao.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
@ -250,7 +256,7 @@ define(function(require) {
* @param {Function} callback(error) * @param {Function} callback(error)
*/ */
KeychainDAO.prototype.setDeviceName = function(deviceName, callback) { KeychainDAO.prototype.setDeviceName = function(deviceName, callback) {
callback(new Error('Not yet implemented!')); this._localDbDao.persist(DB_DEVICENAME, deviceName, callback);
}; };
/** /**
@ -258,15 +264,57 @@ define(function(require) {
* @param {Function} callback(error, deviceSecret:[base64 encoded string]) * @param {Function} callback(error, deviceSecret:[base64 encoded string])
*/ */
KeychainDAO.prototype.getDeviceSecret = function(callback) { KeychainDAO.prototype.getDeviceSecret = function(callback) {
var self = this;
// check if deviceName is already persisted in storage and if not return an error // check if deviceName is already persisted in storage and if not return an error
self._localDbDao.read(DB_DEVICENAME, function(err, deviceName) {
if (err) {
callback(err);
return;
}
// generate random deviceKeys or get from storage if (!deviceName) {
callback(new Error('Device name not set!'));
return;
}
// persist deviceKeys to local storage (in plaintext) readOrGenerateDeviceKey(function(deviceKey) {
generateDeciceSecret(deviceName, deviceKey);
});
});
// encrypt: deviceSecret = Es(deviceKeys, deviceName) -> callback // generate random deviceKey or get from storage
function readOrGenerateDeviceKey(localCallback) {
self._localDbDao.read(DB_DEVICEKEY, function(err, storedDevKey) {
if (err) {
callback(err);
return;
}
callback(new Error('Not yet implemented!')); if (storedDevKey) {
// a device key is already available locally
localCallback(storedDevKey);
return;
}
// generate random deviceKey
var deviceKey = util.random(256);
// persist deviceKey to local storage (in plaintext)
self._localDbDao.persist(DB_DEVICEKEY, deviceKey, function(err) {
if (err) {
callback(err);
return;
}
localCallback(deviceKey);
});
});
}
// encrypt: deviceSecret = Es(deviceKey, deviceName) -> callback
function generateDeciceSecret(deviceName, deviceKey) {
self._crypto.encrypt(deviceName, deviceKey, callback);
}
}; };
/** /**
@ -357,7 +405,7 @@ define(function(require) {
var self = this; var self = this;
// search for user's public key locally // search for user's public key locally
self._localDbDao.list('publickey', 0, null, function(err, allPubkeys) { self._localDbDao.list(DB_PUBLICKEY, 0, null, function(err, allPubkeys) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
@ -477,7 +525,7 @@ define(function(require) {
} }
// lookup in local storage // lookup in local storage
self._localDbDao.read('publickey_' + id, function(err, pubkey) { self._localDbDao.read(DB_PUBLICKEY + '_' + id, function(err, pubkey) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
@ -513,27 +561,27 @@ define(function(require) {
*/ */
KeychainDAO.prototype.listLocalPublicKeys = function(callback) { KeychainDAO.prototype.listLocalPublicKeys = function(callback) {
// search local keyring for public key // search local keyring for public key
this._localDbDao.list('publickey', 0, null, callback); this._localDbDao.list(DB_PUBLICKEY, 0, null, callback);
}; };
KeychainDAO.prototype.removeLocalPublicKey = function(id, callback) { KeychainDAO.prototype.removeLocalPublicKey = function(id, callback) {
this._localDbDao.remove('publickey_' + id, callback); this._localDbDao.remove(DB_PUBLICKEY + '_' + id, callback);
}; };
KeychainDAO.prototype.lookupPrivateKey = function(id, callback) { KeychainDAO.prototype.lookupPrivateKey = function(id, callback) {
// lookup in local storage // lookup in local storage
this._localDbDao.read('privatekey_' + id, callback); this._localDbDao.read(DB_PRIVATEKEY + '_' + id, callback);
}; };
KeychainDAO.prototype.saveLocalPublicKey = function(pubkey, callback) { KeychainDAO.prototype.saveLocalPublicKey = function(pubkey, callback) {
// persist public key (email, _id) // persist public key (email, _id)
var pkLookupKey = 'publickey_' + pubkey._id; var pkLookupKey = DB_PUBLICKEY + '_' + pubkey._id;
this._localDbDao.persist(pkLookupKey, pubkey, callback); this._localDbDao.persist(pkLookupKey, pubkey, callback);
}; };
KeychainDAO.prototype.saveLocalPrivateKey = function(privkey, callback) { KeychainDAO.prototype.saveLocalPrivateKey = function(privkey, callback) {
// persist private key (email, _id) // persist private key (email, _id)
var prkLookupKey = 'privatekey_' + privkey._id; var prkLookupKey = DB_PRIVATEKEY + '_' + privkey._id;
this._localDbDao.persist(prkLookupKey, privkey, callback); this._localDbDao.persist(prkLookupKey, privkey, callback);
}; };

View File

@ -4,18 +4,22 @@ define(function(require) {
var LawnchairDAO = require('js/dao/lawnchair-dao'), var LawnchairDAO = require('js/dao/lawnchair-dao'),
PublicKeyDAO = require('js/dao/publickey-dao'), PublicKeyDAO = require('js/dao/publickey-dao'),
KeychainDAO = require('js/dao/keychain-dao'), KeychainDAO = require('js/dao/keychain-dao'),
PrivateKeyDAO = require('js/dao/privatekey-dao'),
Crypto = require('js/crypto/crypto'),
expect = chai.expect; expect = chai.expect;
var testUser = 'test@example.com'; var testUser = 'test@example.com';
describe('Keychain DAO unit tests', function() { describe('Keychain DAO unit tests', function() {
var keychainDao, lawnchairDaoStub, pubkeyDaoStub; var keychainDao, lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub;
beforeEach(function() { beforeEach(function() {
lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO); lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO);
pubkeyDaoStub = sinon.createStubInstance(PublicKeyDAO); pubkeyDaoStub = sinon.createStubInstance(PublicKeyDAO);
keychainDao = new KeychainDAO(lawnchairDaoStub, pubkeyDaoStub); privkeyDaoStub = new sinon.createStubInstance(PrivateKeyDAO);
cryptoStub = new sinon.createStubInstance(Crypto);
keychainDao = new KeychainDAO(lawnchairDaoStub, pubkeyDaoStub, privkeyDaoStub, cryptoStub);
}); });
afterEach(function() {}); afterEach(function() {});
@ -574,6 +578,84 @@ define(function(require) {
}); });
}); });
describe('setDeviceName', function() {
it('should work', function(done) {
lawnchairDaoStub.persist.yields();
keychainDao.setDeviceName('iPhone', done);
});
});
describe('getDeviceSecret', function() {
it('should fail when device name is not set', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields();
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err.message).to.equal('Device name not set!');
expect(deviceSecret).to.not.exist;
done();
});
});
it('should fail due to erorr when reading device name', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields(42);
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err).to.equal(42);
expect(deviceSecret).to.not.exist;
done();
});
});
it('should fail due to erorr when reading device key', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone');
lawnchairDaoStub.read.withArgs('devicekey').yields(42);
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err).to.equal(42);
expect(deviceSecret).to.not.exist;
done();
});
});
it('should fail due to erorr when storing device key', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone');
lawnchairDaoStub.read.withArgs('devicekey').yields();
lawnchairDaoStub.persist.withArgs('devicekey').yields(42);
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err).to.equal(42);
expect(deviceSecret).to.not.exist;
done();
});
});
it('should work when device key is not set', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone');
lawnchairDaoStub.read.withArgs('devicekey').yields();
lawnchairDaoStub.persist.withArgs('devicekey').yields();
cryptoStub.encrypt.yields(null, 'secret');
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err).to.not.exist;
expect(deviceSecret).to.equal('secret');
done();
});
});
it('should work when device key is set', function(done) {
lawnchairDaoStub.read.withArgs('devicename').yields(null, 'iPhone');
lawnchairDaoStub.read.withArgs('devicekey').yields(null, 'key');
cryptoStub.encrypt.withArgs('iPhone', 'key').yields(null, 'secret');
keychainDao.getDeviceSecret(function(err, deviceSecret) {
expect(err).to.not.exist;
expect(deviceSecret).to.equal('secret');
done();
});
});
});
describe('put user keypair', function() { describe('put user keypair', function() {
it('should fail', function(done) { it('should fail', function(done) {
var keypair = { var keypair = {