mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-28 03:29:20 +03:00
Merge pull request #999 from esroyo/gpg-key-multiple-addresses
Gpg key multiple addresses
This commit is contained in:
commit
dd824179f1
12 changed files with 198 additions and 77 deletions
|
|
@ -426,25 +426,36 @@ class AppUser extends AbstractApp
|
|||
if (oItem && oItem.primaryKey)
|
||||
{
|
||||
var
|
||||
|
||||
aEmails = [],
|
||||
aUsers = [],
|
||||
oPrimaryUser = oItem.getPrimaryUser(),
|
||||
sUser = (oPrimaryUser && oPrimaryUser.user) ? oPrimaryUser.user.userId.userid
|
||||
: (oItem.users && oItem.users[0] ? oItem.users[0].userId.userid : '')
|
||||
;
|
||||
|
||||
oEmail.clear();
|
||||
oEmail.mailsoParse(sUser);
|
||||
if (oItem.users) {
|
||||
_.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(
|
||||
iIndex,
|
||||
oItem.primaryKey.getFingerprint(),
|
||||
oItem.primaryKey.getKeyId().toHex().toLowerCase(),
|
||||
sUser,
|
||||
oEmail.email,
|
||||
aUsers,
|
||||
aEmails,
|
||||
oItem.isPrivate(),
|
||||
oItem.armor())
|
||||
oItem.armor(),
|
||||
sUser)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,19 @@
|
|||
*/
|
||||
MessageModel.prototype.getRecipientsEmails = function ()
|
||||
{
|
||||
return _.compact(_.uniq(_.map(this.to.concat(this.cc), function (oItem) {
|
||||
return this.getEmails(['to', 'cc']);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} aProperties
|
||||
* @return {Array}
|
||||
*/
|
||||
MessageModel.prototype.getEmails = function (aProperties)
|
||||
{
|
||||
var self = this;
|
||||
return _.compact(_.uniq(_.map(_.reduce(aProperties, function (aCarry, sProperty) {
|
||||
return aCarry.concat(self[sProperty]);
|
||||
}, []), function (oItem) {
|
||||
return oItem ? oItem.email : '';
|
||||
})));
|
||||
};
|
||||
|
|
@ -1033,4 +1045,4 @@
|
|||
|
||||
module.exports = MessageModel;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
|||
|
|
@ -18,23 +18,25 @@
|
|||
* @param {string} iIndex
|
||||
* @param {string} sGuID
|
||||
* @param {string} sID
|
||||
* @param {string} sUserID
|
||||
* @param {string} sEmail
|
||||
* @param {array} aUserIDs
|
||||
* @param {array} aEmails
|
||||
* @param {boolean} bIsPrivate
|
||||
* @param {string} sArmor
|
||||
* @param {string} sUserID
|
||||
* @constructor
|
||||
*/
|
||||
function OpenPgpKeyModel(iIndex, sGuID, sID, sUserID, sEmail, bIsPrivate, sArmor)
|
||||
function OpenPgpKeyModel(iIndex, sGuID, sID, aUserIDs, aEmails, bIsPrivate, sArmor, sUserID)
|
||||
{
|
||||
AbstractModel.call(this, 'OpenPgpKeyModel');
|
||||
|
||||
this.index = iIndex;
|
||||
this.id = sID;
|
||||
this.guid = sGuID;
|
||||
this.user = sUserID;
|
||||
this.email = sEmail;
|
||||
this.users = aUserIDs;
|
||||
this.emails = aEmails;
|
||||
this.armor = sArmor;
|
||||
this.isPrivate = !!bIsPrivate;
|
||||
this.selectUser(sUserID);
|
||||
|
||||
this.deleteAccess = ko.observable(false);
|
||||
}
|
||||
|
|
@ -45,7 +47,9 @@
|
|||
OpenPgpKeyModel.prototype.id = '';
|
||||
OpenPgpKeyModel.prototype.guid = '';
|
||||
OpenPgpKeyModel.prototype.user = '';
|
||||
OpenPgpKeyModel.prototype.users = [];
|
||||
OpenPgpKeyModel.prototype.email = '';
|
||||
OpenPgpKeyModel.prototype.emails = [];
|
||||
OpenPgpKeyModel.prototype.armor = '';
|
||||
OpenPgpKeyModel.prototype.isPrivate = false;
|
||||
|
||||
|
|
@ -74,6 +78,26 @@
|
|||
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;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
PgpUserStore.prototype.findPublicKeysByEmail = function (sEmail)
|
||||
{
|
||||
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];
|
||||
}), true));
|
||||
};
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
PgpUserStore.prototype.findPublicKeyByEmailNotNative = function (sEmail)
|
||||
{
|
||||
return _.find(this.openpgpkeysPublic(), function (oItem) {
|
||||
return oItem && sEmail === oItem.email;
|
||||
return oItem && -1 !== oItem.emails.indexOf(sEmail);
|
||||
}) || null;
|
||||
};
|
||||
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
PgpUserStore.prototype.findPrivateKeyByEmailNotNative = function (sEmail)
|
||||
{
|
||||
return _.find(this.openpgpkeysPrivate(), function (oItem) {
|
||||
return oItem && sEmail === oItem.email;
|
||||
return oItem && -1 !== oItem.emails.indexOf(sEmail);
|
||||
}) || null;
|
||||
};
|
||||
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
oPrivateKeys = [],
|
||||
oPrivateKey = null,
|
||||
oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
|
||||
return oItem && sEmail === oItem.email;
|
||||
return oItem && -1 !== oItem.emails.indexOf(sEmail);
|
||||
})
|
||||
;
|
||||
|
||||
|
|
@ -292,7 +292,7 @@
|
|||
bEncrypted = mDom.hasClass('encrypted'),
|
||||
bSigned = mDom.hasClass('signed'),
|
||||
oVerControl = null,
|
||||
aRecipients = oRainLoopMessage ? oRainLoopMessage.getRecipientsEmails() : [],
|
||||
aRecipients = oRainLoopMessage ? oRainLoopMessage.getEmails(['from', 'to', 'cc']) : [],
|
||||
sData = ''
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,14 @@
|
|||
min-height: 40px;
|
||||
|
||||
&-wrp {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:hover {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&:hover .key-list__item-name {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&.empty {
|
||||
text-align: center;
|
||||
|
|
@ -48,33 +54,39 @@
|
|||
|
||||
color: #333;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 4px;
|
||||
|
||||
&-delete {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
margin-right: 5px;
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-right: 5px;
|
||||
&-delete {
|
||||
cursor: pointer;
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&-names {
|
||||
color: #333;
|
||||
display: inline;
|
||||
|
||||
&.empty {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
&-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-error {
|
||||
margin-right: 5px;
|
||||
color: red;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&-hash {
|
||||
margin-right: 5px;
|
||||
color: #aaa;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +94,10 @@
|
|||
.key-actions {
|
||||
margin-top: 10px;
|
||||
min-height: 40px;
|
||||
|
||||
select option.even {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,12 +119,18 @@
|
|||
white-space: nowrap;
|
||||
|
||||
&__radio {
|
||||
padding-right: 5px;
|
||||
padding: 3px 5px 0 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&__name {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&__names {
|
||||
display: inline-block;
|
||||
|
||||
&:hover .key-list__item__name {
|
||||
border-bottom: 1px dashed #555;
|
||||
}
|
||||
}
|
||||
|
|
@ -129,4 +151,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
.open-pgp-key-img {
|
||||
|
||||
margin-right: 10px;
|
||||
vertical-align: top;
|
||||
|
||||
.svg-icon {
|
||||
width: 12px;
|
||||
|
|
@ -33,6 +34,11 @@
|
|||
line-height: 22px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.open-pgp-key-user-address:first-child {
|
||||
line-height: 30px;
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
.open-pgp-key-item {
|
||||
|
|
@ -61,4 +67,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
line-height: 17px;
|
||||
font-size: 16px;
|
||||
vertical-align: text-top;
|
||||
|
||||
&.disabled,
|
||||
.disabled & {
|
||||
color: grey;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-folder, .icon-folder-add, .icon-list {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@
|
|||
var self = this;
|
||||
|
||||
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('');
|
||||
|
||||
|
|
@ -54,13 +62,17 @@
|
|||
}, this);
|
||||
|
||||
this.publicKeysOptions = ko.computed(function () {
|
||||
return _.compact(_.map(PgpStore.openpgpkeysPublic(), function (oKey) {
|
||||
return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null : {
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + oKey.user,
|
||||
'key': oKey
|
||||
};
|
||||
}));
|
||||
return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPublic(), function (oKey, iIndex) {
|
||||
return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null :
|
||||
_.map(oKey.users, function (sUser) {
|
||||
return {
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser,
|
||||
'key': oKey,
|
||||
'class': iIndex % 2 ? 'odd' : 'even'
|
||||
};
|
||||
});
|
||||
}), true));
|
||||
});
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
|
|
@ -236,7 +248,8 @@
|
|||
aKeys.push({
|
||||
'empty': !oOption.key,
|
||||
'selected': ko.observable(!!oOption.key),
|
||||
'user': oOption.key.user,
|
||||
'removable': this.signKey().id !== oOption.key.id,
|
||||
'users': oOption.key.users,
|
||||
'hash': oOption.key.id.substr(-8).toUpperCase(),
|
||||
'key': oOption.key
|
||||
});
|
||||
|
|
@ -360,11 +373,12 @@
|
|||
if (oIdentity && oIdentity.email())
|
||||
{
|
||||
sEmail = oIdentity.email();
|
||||
aRec.unshift(sEmail);
|
||||
oKey = PgpStore.findPrivateKeyByEmailNotNative(sEmail);
|
||||
if (oKey)
|
||||
{
|
||||
this.signKey({
|
||||
'user': oKey.user || sEmail,
|
||||
'users': oKey.users || [sEmail],
|
||||
'hash': oKey.id.substr(-8).toUpperCase(),
|
||||
'key': oKey
|
||||
});
|
||||
|
|
@ -378,16 +392,19 @@
|
|||
|
||||
if (aRec && 0 < aRec.length)
|
||||
{
|
||||
this.encryptKeys(_.compact(_.map(aRec, function (sEmail) {
|
||||
this.encryptKeys(_.uniq(_.compact(_.map(aRec, function (sEmail) {
|
||||
var oKey = PgpStore.findPublicKeyByEmailNotNative(sEmail) || null;
|
||||
return {
|
||||
'empty': !oKey,
|
||||
'selected': ko.observable(!!oKey),
|
||||
'user': oKey ? (oKey.user || sEmail) : sEmail,
|
||||
'removable': oIdentity && oIdentity.email() && oIdentity.email() !== sEmail,
|
||||
'users': oKey ? (oKey.users || [sEmail]) : [sEmail],
|
||||
'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '',
|
||||
'key': oKey
|
||||
};
|
||||
})));
|
||||
})), function (oEncryptKey) {
|
||||
return oEncryptKey.hash;
|
||||
}));
|
||||
|
||||
if (0 < this.encryptKeys().length)
|
||||
{
|
||||
|
|
@ -400,4 +417,4 @@
|
|||
|
||||
module.exports = ComposeOpenPgpPopupView;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
|||
|
|
@ -184,4 +184,4 @@ _.delay(_.bind(function() {
|
|||
|
||||
module.exports = MessageOpenPgpPopupView;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
|||
|
|
@ -27,12 +27,16 @@
|
|||
No private key found
|
||||
</div>
|
||||
<div class="key-list-wrp" data-bind="visible: signKey">
|
||||
<div class="key-list__item">
|
||||
<div class="key-list__item-hash">
|
||||
<div class="key-list__item row-fluid">
|
||||
<div class="key-list__item-hash span4">
|
||||
(<span data-bind="text: signKey() ? signKey().hash : ''"></span>)
|
||||
</div>
|
||||
<div class="key-list__item-name">
|
||||
<span data-bind="text: signKey() ? signKey().user : ''"></span>
|
||||
<div class="key-list__item-names span8">
|
||||
<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>
|
||||
|
|
@ -54,18 +58,22 @@
|
|||
</div>
|
||||
<div class="key-list-wrp" data-bind="visible: encryptKeys() && encryptKeys().length > 0">
|
||||
<div data-bind="foreach: encryptKeys">
|
||||
<div class="key-list__item">
|
||||
<div class="key-list__item-delete" data-bind="click: $parent.deletePublickKey">
|
||||
<div class="key-list__item row-fluid">
|
||||
<div class="key-list__item-delete span1" data-bind="click: removable ? $parent.deletePublickKey : null, css: {'disabled': !removable}">
|
||||
<i class="icon-trash"></i>
|
||||
</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>)
|
||||
</div>
|
||||
<div class="key-list__item-name" data-bind="css: {'empty': empty}">
|
||||
<span data-bind="text: user"></span>
|
||||
</div>
|
||||
<div class="key-list__item-error" data-bind="visible: empty">
|
||||
(Public key not found)
|
||||
<div class="span8">
|
||||
<span class="key-list__item-names" data-bind="css: {'empty': empty}">
|
||||
<span data-bind="foreach: users">
|
||||
<div class="key-list__item-name" data-bind="text: $data"></div>
|
||||
</span>
|
||||
</span>
|
||||
<span class="key-list__item-error" data-bind="visible: empty">
|
||||
(Public key not found)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -78,19 +86,20 @@
|
|||
<input type="password" class="inputPassword input-block-level i18n"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-i18n="[placeholder]POPUPS_COMPOSE_OPEN_PGP/LABEL_PASSWORD"
|
||||
data-bind="visible: sign, value: password, hasfocus: password.focus, onEnter: doCommand" />
|
||||
data-bind="visible: sign, textInput: password, hasfocus: password.focus, onEnter: doCommand" />
|
||||
</div>
|
||||
<div class="span7" data-bind="visible: encrypt() && 0 < publicKeysOptions().length">
|
||||
<div class="form-inline">
|
||||
<select class="input-block-level" data-bind="options: publicKeysOptions, value: selectedPublicKey,
|
||||
optionsCaption: optionsCaption, optionsText: 'name', optionsValue: 'id',
|
||||
optionsAfterRender: defautOptionsAfterRender"></select>
|
||||
optionsAfterRender: addOptionClass"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn buttonDo" data-bind="command: doCommand, hasfocus: buttonFocus">
|
||||
<button class="btn buttonDo" data-bind="command: doCommand, hasfocus: buttonFocus,
|
||||
enable: (sign() || encrypt()) && (!sign() || (sign() && password().length)) && (!encrypt() || encrypt() && encryptKeys().length > 0)">
|
||||
<i data-bind="css: {'icon-key': !submitRequest(), 'icon-spinner animated': submitRequest()}"></i>
|
||||
|
||||
<span class="i18n" data-bind="visible: sign() && !encrypt()" data-i18n="POPUPS_COMPOSE_OPEN_PGP/BUTTON_SIGN"></span>
|
||||
|
|
|
|||
|
|
@ -18,11 +18,17 @@
|
|||
<div class="controls key-list" data-bind="foreach: privateKeys" style="margin-top: 5px">
|
||||
<div class="key-list__item">
|
||||
<i class="key-list__item__radio icon-radio-unchecked"></i>
|
||||
<span class="key-list__item__name">
|
||||
<span data-bind="text: user"></span>
|
||||
|
||||
<span>[<span data-bind="text: id"></span>]</span>
|
||||
</span>
|
||||
<div class="key-list__item__names">
|
||||
<span data-bind="foreach: users">
|
||||
<div>
|
||||
<span class="key-list__item__name">
|
||||
<span data-bind="text: $data"></span>
|
||||
|
||||
<span>[<span data-bind="text: $parent.id"></span>]</span>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div data-bind="json: $data"></div>-->
|
||||
</div>
|
||||
|
|
@ -31,13 +37,13 @@
|
|||
<label class="i18n control-label" data-i18n="POPUPS_MESSAGE_OPEN_PGP/LABEL_PASSWORD"></label>
|
||||
<div class="controls">
|
||||
<input type="password" class="inputPassword input-xlarge" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="value: password, hasfocus: password.focus, onEnter: doCommand" />
|
||||
data-bind="textInput: password, hasfocus: password.focus, onEnter: doCommand" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn buttonDo" data-bind="command: doCommand, hasfocus: buttonFocus">
|
||||
<button class="btn buttonDo" data-bind="command: doCommand, hasfocus: buttonFocus, enable: password().length > 0">
|
||||
<i data-bind="css: {'icon-key': !submitRequest(), 'icon-spinner animated': submitRequest()}"></i>
|
||||
|
||||
<span class="i18n" data-i18n="POPUPS_MESSAGE_OPEN_PGP/BUTTON_DECRYPT"></span>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,11 @@
|
|||
<span class="open-pgp-key-img i18n" data-i18n="[title]SETTINGS_OPEN_PGP/TITLE_PRIVATE">
|
||||
<i class="icon-lock"></i>
|
||||
</span>
|
||||
<span class="open-pgp-key-user" data-bind="text: user"></span>
|
||||
<span class="open-pgp-key-user">
|
||||
<!-- ko foreach: users -->
|
||||
<div class="open-pgp-key-user-address" data-bind="text: $data"></div>
|
||||
<!-- /ko -->
|
||||
</span>
|
||||
<a class="btn btn-small btn-small-small btn-danger pull-right button-delete button-delete-transitions" data-bind="css: {'delete-access': deleteAccess()}, click: function(oOpenPGP) { $root.deleteOpenPgpKey(oOpenPGP); }">
|
||||
<span class="i18n" data-i18n="SETTINGS_OPEN_PGP/DELETING_ASK"></span>
|
||||
</a>
|
||||
|
|
@ -56,8 +60,13 @@
|
|||
<span class="open-pgp-key-img i18n" data-i18n="[title]SETTINGS_OPEN_PGP/TITLE_PUBLIC">
|
||||
<i class="icon-key"></i>
|
||||
</span>
|
||||
<span class="open-pgp-key-user" data-bind="text: user"></span>
|
||||
(<span class="open-pgp-key-id" data-bind="text: id"></span>)
|
||||
<span class="open-pgp-key-user">
|
||||
<!-- ko foreach: users -->
|
||||
<div class="open-pgp-key-user-address">
|
||||
<span data-bind="text: $data"></span> (<span class="open-pgp-key-id" data-bind="text: $parent.id"></span>)
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</span>
|
||||
<a class="btn btn-small btn-small-small btn-danger pull-right button-delete button-delete-transitions" data-bind="css: {'delete-access': deleteAccess()}, click: function(oOpenPGP) { $root.deleteOpenPgpKey(oOpenPGP); }">
|
||||
<span class="i18n" data-i18n="SETTINGS_OPEN_PGP/DELETING_ASK"></span>
|
||||
</a>
|
||||
|
|
@ -76,4 +85,4 @@
|
|||
<!-- /ko -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue