Skip to content

Commit

Permalink
OpenPGP Key Storage (Settings) (#53)
Browse files Browse the repository at this point in the history
Import, Delete, Generate, View
  • Loading branch information
RainLoop committed Mar 12, 2014
1 parent 5a5c6af commit 5ece4cc
Show file tree
Hide file tree
Showing 47 changed files with 1,333 additions and 539 deletions.
7 changes: 6 additions & 1 deletion Gruntfile.js
Expand Up @@ -253,6 +253,7 @@ module.exports = function (grunt) {

"dev/Storages/LocalStorages/CookieDriver.js",
"dev/Storages/LocalStorages/LocalStorageDriver.js",
"dev/Storages/LocalStorages/OpenPgpLocalStorageDriver.js",
"dev/Storages/LocalStorage.js",

"dev/Knoin/AbstractBoot.js",
Expand All @@ -269,6 +270,7 @@ module.exports = function (grunt) {
"dev/Models/FolderModel.js",
"dev/Models/AccountModel.js",
"dev/Models/IdentityModel.js",
"dev/Models/OpenPgpKeyModel.js",

"dev/ViewModels/PopupsFolderClearViewModel.js",
"dev/ViewModels/PopupsFolderCreateViewModel.js",
Expand All @@ -277,10 +279,12 @@ module.exports = function (grunt) {
"dev/ViewModels/PopupsContactsViewModel.js",
"dev/ViewModels/PopupsAdvancedSearchViewModel.js",
"dev/ViewModels/PopupsAddAccountViewModel.js",
"dev/ViewModels/PopupsAddOpenPgpKeyViewModel.js",
"dev/ViewModels/PopupsViewOpenPgpKeyViewModel.js",
"dev/ViewModels/PopupsGenerateNewOpenPgpKeyViewModel.js",
"dev/ViewModels/PopupsIdentityViewModel.js",
"dev/ViewModels/PopupsLanguagesViewModel.js",
"dev/ViewModels/PopupsAskViewModel.js",
"dev/ViewModels/PopupsPgpKey.js",

"dev/ViewModels/LoginViewModel.js",

Expand All @@ -301,6 +305,7 @@ module.exports = function (grunt) {
"dev/Settings/Identity.js",
"dev/Settings/Identities.js",
"dev/Settings/Social.js",
"dev/Settings/OpenPGP.js",
"dev/Settings/ChangePassword.js",
"dev/Settings/Folders.js",
"dev/Settings/Themes.js",
Expand Down
40 changes: 39 additions & 1 deletion dev/Boots/RainLoopApp.js
Expand Up @@ -190,6 +190,36 @@ RainLoopApp.prototype.folders = function (fCallback)
}, this));
};

RainLoopApp.prototype.reloadOpenPgpKeys = function ()
{
if (Globals.bAllowOpenPGP)
{
var
aKeys = [],
oOpenpgpKeyring = RL.data().openpgpKeyring,
oOpenpgpKeys = oOpenpgpKeyring ? oOpenpgpKeyring.keys : []
;

_.each(oOpenpgpKeys, function (oItem, iIndex) {
if (oItem)
{
var
aIDs = _.map(oItem.getKeyIds(), function (oID) {
return oID ? oID.toHex() : '';
})
;

aKeys.push(
new OpenPgpKeyModel(iIndex, aIDs.join(', '), oItem.getUserIds().join(', '),
oItem.isPrivate(), oItem.armor())
);
}
});

RL.data().openpgpkeys(aKeys);
}
};

RainLoopApp.prototype.accountsAndIdentities = function ()
{
var oRainLoopData = RL.data();
Expand Down Expand Up @@ -739,6 +769,11 @@ RainLoopApp.prototype.bootstart = function ()
{
Utils.removeSettingsViewModel(SettingsIdentities);
}

if (!RL.settingsGet('OpenPGP'))
{
Utils.removeSettingsViewModel(SettingsOpenPGP);
}

if (!bGoogle && !bFacebook && !bTwitter)
{
Expand Down Expand Up @@ -795,9 +830,12 @@ RainLoopApp.prototype.bootstart = function ()
'success': function () {
if (window.openpgp)
{
// window.console.log(window.openpgp);
RL.data().openpgpKeyring = new window.openpgp.Keyring(new OpenPgpLocalStorageDriver());

Globals.bAllowOpenPGP = true;
RL.pub('openpgp.init');

RL.reloadOpenPgpKeys();
}
}
});
Expand Down
31 changes: 26 additions & 5 deletions dev/Common/Utils.js
Expand Up @@ -331,12 +331,13 @@ Utils.i18nToNode = function (oElement)
{
jqThis.attr('placeholder', Utils.i18n(sKey));
}

sKey = jqThis.data('i18n-title');
if (sKey)
{
jqThis.attr('title', Utils.i18n(sKey));
}
}
// sKey = jqThis.data('i18n-title');
// if (sKey)
// {
// jqThis.attr('title', Utils.i18n(sKey));
// }
});
});
};
Expand Down Expand Up @@ -1695,3 +1696,23 @@ Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount)
return aResult;
};
};

Utils.selectElement = function (element)
{
/* jshint onevar: false */
if (window.getSelection)
{
var sel = window.getSelection();
sel.removeAllRanges();
var range = document.createRange();
range.selectNodeContents(element);
sel.addRange(range);
}
else if (document.selection)
{
var textRange = document.body.createTextRange();
textRange.moveToElementText(element);
textRange.select();
}
/* jshint onevar: true */
};
15 changes: 15 additions & 0 deletions dev/Knoin/AbstractViewModel.js
Expand Up @@ -7,6 +7,7 @@
*/
function KnoinAbstractViewModel(sPosition, sTemplate)
{
this.bDisabeCloseOnEsc = false;
this.sPosition = Utils.pString(sPosition);
this.sTemplate = Utils.pString(sTemplate);

Expand Down Expand Up @@ -59,3 +60,17 @@ KnoinAbstractViewModel.prototype.viewModelPosition = function ()
KnoinAbstractViewModel.prototype.cancelCommand = KnoinAbstractViewModel.prototype.closeCommand = function ()
{
};

KnoinAbstractViewModel.prototype.registerPopupEscapeKey = function ()
{
var self = this;
$window.on('keydown', function (oEvent) {
if (oEvent && Enums.EventKeyCode.Esc === oEvent.keyCode && self.modalVisibility())
{
Utils.delegateRun(self, 'cancelCommand');
return false;
}

return true;
});
};
4 changes: 4 additions & 0 deletions dev/Knoin/Knoin.js
Expand Up @@ -115,6 +115,10 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)

ko.applyBindings(oViewModel, oViewModelDom[0]);
Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
if (oViewModel && 'Popups' === sPosition && !oViewModel.bDisabeCloseOnEsc)
{
oViewModel.registerPopupEscapeKey();
}

Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
}
Expand Down
26 changes: 26 additions & 0 deletions dev/Models/OpenPgpKeyModel.js
@@ -0,0 +1,26 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */

/**
* @param {string} iIndex
* @param {string} sID
* @param {string} sUserID
* @param {boolean} bIsPrivate
* @param {string} sArmor
* @constructor
*/
function OpenPgpKeyModel(iIndex, sID, sUserID, bIsPrivate, sArmor)
{
this.index = iIndex;
this.id = sID;
this.user = sUserID;
this.armor = sArmor;
this.isPrivate = !!bIsPrivate;

this.deleteAccess = ko.observable(false);
}

OpenPgpKeyModel.prototype.index = 0;
OpenPgpKeyModel.prototype.id = '';
OpenPgpKeyModel.prototype.user = '';
OpenPgpKeyModel.prototype.armor = '';
OpenPgpKeyModel.prototype.isPrivate = false;
83 changes: 83 additions & 0 deletions dev/Settings/OpenPGP.js
@@ -0,0 +1,83 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */

/**
* @constructor
*/
function SettingsOpenPGP()
{
this.openpgpkeys = RL.data().openpgpkeys;

this.openpgpkeysPublic = ko.computed(function () {
return _.filter(this.openpgpkeys(), function (oItem) {
return !!(oItem && !oItem.isPrivate);
});
}, this);

this.openpgpkeysPrivate = ko.computed(function () {
return _.filter(this.openpgpkeys(), function (oItem) {
return !!(oItem && oItem.isPrivate);
});
}, this);

this.openPgpKeyForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this,
function (oPrev) {
if (oPrev)
{
oPrev.deleteAccess(false);
}
}, function (oNext) {
if (oNext)
{
oNext.deleteAccess(true);
}
}
]});
}

Utils.addSettingsViewModel(SettingsOpenPGP, 'SettingsOpenPGP', 'SETTINGS_LABELS/LABEL_OPEN_PGP_NAME', 'openpgp');

SettingsOpenPGP.prototype.addOpenPgpKey = function ()
{
kn.showScreenPopup(PopupsAddOpenPgpKeyViewModel);
};

SettingsOpenPGP.prototype.generateOpenPgpKey = function ()
{
kn.showScreenPopup(PopupsGenerateNewOpenPgpKeyViewModel);
};

SettingsOpenPGP.prototype.viewOpenPgpKey = function (oOpenPgpKey)
{
if (oOpenPgpKey)
{
kn.showScreenPopup(PopupsViewOpenPgpKeyViewModel, [oOpenPgpKey]);
}
};

/**
* @param {OpenPgpKeyModel} oOpenPgpKeyToRemove
*/
SettingsOpenPGP.prototype.deleteOpenPgpKey = function (oOpenPgpKeyToRemove)
{
if (oOpenPgpKeyToRemove && oOpenPgpKeyToRemove.deleteAccess())
{
this.openPgpKeyForDeletion(null);

var
oOpenpgpKeyring = RL.data().openpgpKeyring,
fRemoveAccount = function (oOpenPgpKey) {
return oOpenPgpKeyToRemove === oOpenPgpKey;
}
;

if (oOpenPgpKeyToRemove && oOpenpgpKeyring)
{
this.openpgpkeys.remove(fRemoveAccount);

oOpenpgpKeyring.removeKey(oOpenPgpKeyToRemove.index);
oOpenpgpKeyring.store();

RL.reloadOpenPgpKeys();
}
}
};
5 changes: 2 additions & 3 deletions dev/Storages/LocalStorages/LocalStorageDriver.js
Expand Up @@ -12,7 +12,6 @@ LocalStorageDriver.supported = function ()
return !!window.localStorage;
};


/**
* @param {string} sKey
* @param {*} mData
Expand All @@ -21,14 +20,14 @@ LocalStorageDriver.supported = function ()
LocalStorageDriver.prototype.set = function (sKey, mData)
{
var
mCokieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
mCookieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
bResult = false,
mResult = null
;

try
{
mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
mResult = null === mCookieValue ? null : JSON.parse(mCookieValue);
if (!mResult)
{
mResult = {};
Expand Down
60 changes: 60 additions & 0 deletions dev/Storages/LocalStorages/OpenPgpLocalStorageDriver.js
@@ -0,0 +1,60 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */

/**
* @constructor
*/
function OpenPgpLocalStorageDriver()
{
}

/*
* Declare the localstore itemname
*/
OpenPgpLocalStorageDriver.prototype.item = 'armoredRainLoopKeys';

/**
* Load the keyring from HTML5 local storage and initializes this instance.
* @return {Array<module:key~Key>} array of keys retrieved from localstore
*/
OpenPgpLocalStorageDriver.prototype.load = function ()
{
var
iIndex = 0,
iLen = 0,
aKeys = [],
aArmoredKeys = JSON.parse(window.localStorage.getItem(this.item))
;

if (aArmoredKeys && 0 < aArmoredKeys.length)
{
for (iLen = aArmoredKeys.length; iIndex < iLen; iIndex++)
{
aKeys.push(
window.openpgp.key.readArmored(aArmoredKeys[iIndex]).keys[0]
);
}
}

return aKeys;
};

/**
* Saves the current state of the keyring to HTML5 local storage.
* The privateKeys array and publicKeys array gets Stringified using JSON
* @param {Array<module:key~Key>} aKeys array of keys to save in localstore
*/
OpenPgpLocalStorageDriver.prototype.store = function (aKeys)
{
var
iIndex = 0,
iLen = aKeys.length,
aArmoredKeys = []
;

for (; iIndex < iLen; iIndex++)
{
aArmoredKeys.push(aKeys[iIndex].armor());
}

window.localStorage.setItem(this.item, JSON.stringify(aArmoredKeys));
};
3 changes: 3 additions & 0 deletions dev/Storages/WebMailData.js
Expand Up @@ -343,6 +343,9 @@ function WebMailDataStorage()

// other
this.useKeyboardShortcuts = ko.observable(true);

this.openpgpkeys = ko.observableArray([]);
this.openpgpKeyring = null;

// google
this.googleActions = ko.observable(false);
Expand Down

0 comments on commit 5ece4cc

Please sign in to comment.