Encrypt/decrypt with multiple addresses in a single GPG key

This commit is contained in:
Carles Escrig Royo 2016-04-06 20:26:29 +02:00
parent d14375d022
commit a34da5de0d
No known key found for this signature in database
GPG key ID: 5E6F07C704111773
8 changed files with 141 additions and 62 deletions

View file

@ -426,25 +426,36 @@ class AppUser extends AbstractApp
if (oItem && oItem.primaryKey) if (oItem && oItem.primaryKey)
{ {
var var
aEmails = [],
aUsers = [],
oPrimaryUser = oItem.getPrimaryUser(), oPrimaryUser = oItem.getPrimaryUser(),
sUser = (oPrimaryUser && oPrimaryUser.user) ? oPrimaryUser.user.userId.userid sUser = (oPrimaryUser && oPrimaryUser.user) ? oPrimaryUser.user.userId.userid
: (oItem.users && oItem.users[0] ? oItem.users[0].userId.userid : '') : (oItem.users && oItem.users[0] ? oItem.users[0].userId.userid : '')
; ;
oEmail.clear(); if (oItem.users) {
oEmail.mailsoParse(sUser); _.each(oItem.users, (oItem) => {
oEmail.clear();
oEmail.mailsoParse(oItem.userId.userid);
if (oEmail.validate())
{
aEmails.push(oEmail.email);
aUsers.push(oItem.userId.userid);
}
});
}
if (oEmail.validate()) if (aEmails.length)
{ {
aKeys.push(new OpenPgpKeyModel( aKeys.push(new OpenPgpKeyModel(
iIndex, iIndex,
oItem.primaryKey.getFingerprint(), oItem.primaryKey.getFingerprint(),
oItem.primaryKey.getKeyId().toHex().toLowerCase(), oItem.primaryKey.getKeyId().toHex().toLowerCase(),
sUser, aUsers,
oEmail.email, aEmails,
oItem.isPrivate(), oItem.isPrivate(),
oItem.armor()) oItem.armor(),
sUser)
); );
} }
} }

View file

@ -18,23 +18,25 @@
* @param {string} iIndex * @param {string} iIndex
* @param {string} sGuID * @param {string} sGuID
* @param {string} sID * @param {string} sID
* @param {string} sUserID * @param {array} aUserIDs
* @param {string} sEmail * @param {array} aEmails
* @param {boolean} bIsPrivate * @param {boolean} bIsPrivate
* @param {string} sArmor * @param {string} sArmor
* @param {string} sUserID
* @constructor * @constructor
*/ */
function OpenPgpKeyModel(iIndex, sGuID, sID, sUserID, sEmail, bIsPrivate, sArmor) function OpenPgpKeyModel(iIndex, sGuID, sID, aUserIDs, aEmails, bIsPrivate, sArmor, sUserID)
{ {
AbstractModel.call(this, 'OpenPgpKeyModel'); AbstractModel.call(this, 'OpenPgpKeyModel');
this.index = iIndex; this.index = iIndex;
this.id = sID; this.id = sID;
this.guid = sGuID; this.guid = sGuID;
this.user = sUserID; this.users = aUserIDs;
this.email = sEmail; this.emails = aEmails;
this.armor = sArmor; this.armor = sArmor;
this.isPrivate = !!bIsPrivate; this.isPrivate = !!bIsPrivate;
this.selectUser(sUserID);
this.deleteAccess = ko.observable(false); this.deleteAccess = ko.observable(false);
} }
@ -45,7 +47,9 @@
OpenPgpKeyModel.prototype.id = ''; OpenPgpKeyModel.prototype.id = '';
OpenPgpKeyModel.prototype.guid = ''; OpenPgpKeyModel.prototype.guid = '';
OpenPgpKeyModel.prototype.user = ''; OpenPgpKeyModel.prototype.user = '';
OpenPgpKeyModel.prototype.users = [];
OpenPgpKeyModel.prototype.email = ''; OpenPgpKeyModel.prototype.email = '';
OpenPgpKeyModel.prototype.emails = [];
OpenPgpKeyModel.prototype.armor = ''; OpenPgpKeyModel.prototype.armor = '';
OpenPgpKeyModel.prototype.isPrivate = false; OpenPgpKeyModel.prototype.isPrivate = false;
@ -74,6 +78,26 @@
return oKey && oKey.keys ? oKey.keys : null; return oKey && oKey.keys ? oKey.keys : null;
}; };
OpenPgpKeyModel.prototype.select = function (sPattern, sProperty)
{
var index = this[sProperty].indexOf(sPattern);
if (index !== -1) {
this.user = this.users[index];
this.email = this.emails[index];
}
}
OpenPgpKeyModel.prototype.selectUser = function (sUser)
{
this.select(sUser, 'users');
}
OpenPgpKeyModel.prototype.selectEmail = function (sEmail)
{
this.select(sEmail, 'emails');
}
module.exports = OpenPgpKeyModel; module.exports = OpenPgpKeyModel;
}()); }());

View file

@ -59,7 +59,7 @@
PgpUserStore.prototype.findPublicKeysByEmail = function (sEmail) PgpUserStore.prototype.findPublicKeysByEmail = function (sEmail)
{ {
return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), function (oItem) { return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), function (oItem) {
var oKey = oItem && sEmail === oItem.email ? oItem : null; var oKey = oItem && -1 !== oItem.emails.indexOf(sEmail) ? oItem : null;
return oKey ? oKey.getNativeKeys() : [null]; return oKey ? oKey.getNativeKeys() : [null];
}), true)); }), true));
}; };
@ -99,7 +99,7 @@
PgpUserStore.prototype.findPublicKeyByEmailNotNative = function (sEmail) PgpUserStore.prototype.findPublicKeyByEmailNotNative = function (sEmail)
{ {
return _.find(this.openpgpkeysPublic(), function (oItem) { return _.find(this.openpgpkeysPublic(), function (oItem) {
return oItem && sEmail === oItem.email; return oItem && -1 !== oItem.emails.indexOf(sEmail);
}) || null; }) || null;
}; };
@ -110,7 +110,7 @@
PgpUserStore.prototype.findPrivateKeyByEmailNotNative = function (sEmail) PgpUserStore.prototype.findPrivateKeyByEmailNotNative = function (sEmail)
{ {
return _.find(this.openpgpkeysPrivate(), function (oItem) { return _.find(this.openpgpkeysPrivate(), function (oItem) {
return oItem && sEmail === oItem.email; return oItem && -1 !== oItem.emails.indexOf(sEmail);
}) || null; }) || null;
}; };
@ -125,7 +125,7 @@
oPrivateKeys = [], oPrivateKeys = [],
oPrivateKey = null, oPrivateKey = null,
oKey = _.find(this.openpgpkeysPrivate(), function (oItem) { oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
return oItem && sEmail === oItem.email; return oItem && -1 !== oItem.emails.indexOf(sEmail);
}) })
; ;

View file

@ -33,8 +33,14 @@
min-height: 40px; min-height: 40px;
&-wrp { &-wrp {
overflow: hidden;
text-overflow: ellipsis; &:hover {
overflow: auto;
}
&:hover .key-list__item-name {
overflow: visible;
}
&.empty { &.empty {
text-align: center; text-align: center;
@ -48,33 +54,35 @@
color: #333; color: #333;
white-space: nowrap; white-space: nowrap;
padding-bottom: 4px;
&-delete { &:last-child {
display: inline; padding-bottom: 0;
cursor: pointer;
margin-right: 5px;
} }
&-name { &-delete {
margin-right: 5px; cursor: pointer;
}
&-names {
color: #333; color: #333;
display: inline;
&.empty { &.empty {
color: red; color: red;
} }
} }
&-name {
overflow: hidden;
text-overflow: ellipsis;
}
&-error { &-error {
margin-right: 5px;
color: red; color: red;
display: inline;
} }
&-hash { &-hash {
margin-right: 5px;
color: #aaa; color: #aaa;
display: inline;
} }
} }
} }
@ -82,6 +90,10 @@
.key-actions { .key-actions {
margin-top: 10px; margin-top: 10px;
min-height: 40px; min-height: 40px;
select option.even {
background-color: #f5f5f5;
}
} }
} }
@ -103,15 +115,21 @@
white-space: nowrap; white-space: nowrap;
&__radio { &__radio {
padding-right: 5px; padding: 3px 5px 0 0;
vertical-align: top;
} }
&__name { &__name {
border-bottom: 1px solid transparent;
&:hover { &:hover {
border-bottom: 1px dashed #555; border-bottom: 1px dashed #555;
} }
} }
&__names {
display: inline-block;
}
} }
} }
} }

View file

@ -31,6 +31,14 @@
var self = this; var self = this;
this.optionsCaption = Translator.i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY'); this.optionsCaption = Translator.i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY');
this.addOptionClass = function (oDomOption, oItem)
{
self.defautOptionsAfterRender(oDomOption, oItem);
if (oItem) {
oDomOption.classList.add(oItem['class']);
}
};
this.notification = ko.observable(''); this.notification = ko.observable('');
@ -54,13 +62,17 @@
}, this); }, this);
this.publicKeysOptions = ko.computed(function () { this.publicKeysOptions = ko.computed(function () {
return _.compact(_.map(PgpStore.openpgpkeysPublic(), function (oKey) { return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPublic(), function (oKey, iIndex) {
return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null : { return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null :
'id': oKey.guid, _.map(oKey.users, function (sUser) {
'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + oKey.user, return {
'key': oKey 'id': oKey.guid,
}; 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser,
})); 'key': oKey,
'class': iIndex % 2 ? 'odd' : 'even'
};
});
}), true));
}); });
this.submitRequest = ko.observable(false); this.submitRequest = ko.observable(false);
@ -236,7 +248,7 @@
aKeys.push({ aKeys.push({
'empty': !oOption.key, 'empty': !oOption.key,
'selected': ko.observable(!!oOption.key), 'selected': ko.observable(!!oOption.key),
'user': oOption.key.user, 'users': oOption.key.users,
'hash': oOption.key.id.substr(-8).toUpperCase(), 'hash': oOption.key.id.substr(-8).toUpperCase(),
'key': oOption.key 'key': oOption.key
}); });
@ -364,7 +376,7 @@
if (oKey) if (oKey)
{ {
this.signKey({ this.signKey({
'user': oKey.user || sEmail, 'users': oKey.users || [sEmail],
'hash': oKey.id.substr(-8).toUpperCase(), 'hash': oKey.id.substr(-8).toUpperCase(),
'key': oKey 'key': oKey
}); });
@ -383,7 +395,7 @@
return { return {
'empty': !oKey, 'empty': !oKey,
'selected': ko.observable(!!oKey), 'selected': ko.observable(!!oKey),
'user': oKey ? (oKey.user || sEmail) : sEmail, 'users': oKey ? (oKey.users || [sEmail]) : [sEmail],
'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '', 'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '',
'key': oKey 'key': oKey
}; };

View file

@ -27,12 +27,16 @@
No private key found No private key found
</div> </div>
<div class="key-list-wrp" data-bind="visible: signKey"> <div class="key-list-wrp" data-bind="visible: signKey">
<div class="key-list__item"> <div class="key-list__item row-fluid">
<div class="key-list__item-hash"> <div class="key-list__item-hash span4">
(<span data-bind="text: signKey() ? signKey().hash : ''"></span>) (<span data-bind="text: signKey() ? signKey().hash : ''"></span>)
</div> </div>
<div class="key-list__item-name"> <div class="key-list__item-names span8">
<span data-bind="text: signKey() ? signKey().user : ''"></span> <div data-bind="if: signKey()">
<div data-bind="foreach: signKey().users">
<div class="key-list__item-name" data-bind="text: $data"></div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -54,18 +58,22 @@
</div> </div>
<div class="key-list-wrp" data-bind="visible: encryptKeys() && encryptKeys().length > 0"> <div class="key-list-wrp" data-bind="visible: encryptKeys() && encryptKeys().length > 0">
<div data-bind="foreach: encryptKeys"> <div data-bind="foreach: encryptKeys">
<div class="key-list__item"> <div class="key-list__item row-fluid">
<div class="key-list__item-delete" data-bind="click: $parent.deletePublickKey"> <div class="key-list__item-delete span1" data-bind="click: $parent.deletePublickKey">
<i class="icon-trash"></i> <i class="icon-trash"></i>
</div> </div>
<div class="key-list__item-hash" data-bind="visible: !empty"> <div class="key-list__item-hash span3" data-bind="visible: !empty">
(<span data-bind="text: hash"></span>) (<span data-bind="text: hash"></span>)
</div> </div>
<div class="key-list__item-name" data-bind="css: {'empty': empty}"> <div class="span8">
<span data-bind="text: user"></span> <span class="key-list__item-names" data-bind="css: {'empty': empty}">
</div> <span data-bind="foreach: users">
<div class="key-list__item-error" data-bind="visible: empty"> <div class="key-list__item-name" data-bind="text: $data"></div>
(Public key not found) </span>
</span>
<span class="key-list__item-error" data-bind="visible: empty">
(Public key not found)
</span>
</div> </div>
</div> </div>
</div> </div>
@ -84,7 +92,7 @@
<div class="form-inline"> <div class="form-inline">
<select class="input-block-level" data-bind="options: publicKeysOptions, value: selectedPublicKey, <select class="input-block-level" data-bind="options: publicKeysOptions, value: selectedPublicKey,
optionsCaption: optionsCaption, optionsText: 'name', optionsValue: 'id', optionsCaption: optionsCaption, optionsText: 'name', optionsValue: 'id',
optionsAfterRender: defautOptionsAfterRender"></select> optionsAfterRender: addOptionClass"></select>
</div> </div>
</div> </div>
</div> </div>

View file

@ -18,11 +18,17 @@
<div class="controls key-list" data-bind="foreach: privateKeys" style="margin-top: 5px"> <div class="controls key-list" data-bind="foreach: privateKeys" style="margin-top: 5px">
<div class="key-list__item"> <div class="key-list__item">
<i class="key-list__item__radio icon-radio-unchecked"></i> <i class="key-list__item__radio icon-radio-unchecked"></i>
<span class="key-list__item__name"> <div class="key-list__item__names">
<span data-bind="text: user"></span> <span data-bind="foreach: users">
&nbsp; <div>
<span>[<span data-bind="text: id"></span>]</span> <span class="key-list__item__name">
</span> <span data-bind="text: $data"></span>
&nbsp;
<span>[<span data-bind="text: $parent.id"></span>]</span>
</span>
</div>
</span>
</div>
</div> </div>
<!--<div data-bind="json: $data"></div>--> <!--<div data-bind="json: $data"></div>-->
</div> </div>