Enigma: Import keys from key-server(s) (#5286)

pull/321/merge
Aleksander Machniak 8 years ago
parent 4361a95820
commit 437aca39e0

@ -7,6 +7,7 @@ CHANGELOG Roundcube Webmail
- Display full message subject in onmouseover on truncated subject in mail view (#5346)
- Searching in both contacts and groups when LDAP addressbook with group_filters option is used
- Update TinyMCE to version 4.3.13 (#5309)
- Enigma: Import keys from key-server(s) (#5286)
- Enigma: Search missing public keys on a key-server in mail compose (#5286)
- Enigma: Delete user keys when using deluser.sh script
- Enigma: Fix redundant list-secret-keys/list-public-keys calls on signing/encryption

@ -19,6 +19,7 @@ Implemented features:
+ Handling of PGP keys attached to incoming messages
+ User preferences to disable plugin features
+ Attaching public keys to email
+ Key server(s) support (search, import)
TODO:
@ -33,7 +34,7 @@ TODO:
- export private keys
- Generate revocation certs
- Search filter to see invalid/expired keys
- Key server(s) support (search, import, upload, refresh)
- Key server(s) support (upload, refresh)
- Mark keys as trusted/untrasted, display appropriate message in verify/decrypt status
- Change attachment icon on messages list for encrypted messages (like vcard_attachment plugin does)
- Support for multi-server installations (store keys in sql database?)

@ -23,6 +23,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.register_command('search', function(props) {return rcmail.enigma_search(props); }, true);
rcmail.register_command('reset-search', function(props) {return rcmail.enigma_search_reset(props); }, true);
rcmail.register_command('plugin.enigma-import', function() { rcmail.enigma_import(); }, true);
rcmail.register_command('plugin.enigma-import-search', function() { rcmail.enigma_import_search(); }, true);
rcmail.register_command('plugin.enigma-key-export', function() { rcmail.enigma_export(); });
rcmail.register_command('plugin.enigma-key-export-selected', function() { rcmail.enigma_export(true); });
rcmail.register_command('plugin.enigma-key-import', function() { rcmail.enigma_key_import(); }, true);
@ -33,6 +34,19 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.addEventListener('responseafterplugin.enigmakeys', function() {
rcmail.enable_command('plugin.enigma-key-export', rcmail.env.rowcount > 0);
});
if (rcmail.gui_objects.importform) {
// make sure Enter key in search input starts searching
// instead of submitting the form
$('#rcmimportsearch').keydown(function(e) {
if (e.which == 13) {
rcmail.enigma_import_search();
return false;
}
});
$('input[type="button"]:first').focus();
}
}
}
else if (rcmail.env.task == 'mail') {
@ -217,6 +231,21 @@ rcube_webmail.prototype.enigma_import = function()
}
};
// Ssearch for key(s) for import
rcube_webmail.prototype.enigma_import_search = function()
{
var form, search;
if (form = this.gui_objects.importform) {
search = $('#rcmimportsearch').val();
if (!search) {
return;
}
this.enigma_find_publickey(search);
}
};
// list row selection handler
rcube_webmail.prototype.enigma_keylist_select = function(list)
{
@ -251,6 +280,8 @@ rcube_webmail.prototype.enigma_loadframe = function(url)
if (!url && (win = window.frames[this.env.contentframe])) {
if (win.location && win.location.href.indexOf(this.env.blankpage) < 0)
win.location.href = this.env.blankpage;
if (this.env.frame_lock)
this.set_busy(false, null, this.env.frame_lock);
return;
}
@ -297,8 +328,11 @@ rcube_webmail.prototype.enigma_search_reset = function(props)
};
// Keys/certs listing
rcube_webmail.prototype.enigma_list = function(page)
rcube_webmail.prototype.enigma_list = function(page, reset_frame)
{
if (this.is_framed())
return parent.rcmail.enigma_list(page, reset_frame);
var params = {'_a': 'list'},
lock = this.set_busy(true, 'loading');
@ -309,7 +343,7 @@ rcube_webmail.prototype.enigma_list = function(page)
if (page)
params._p = page;
this.enigma_clear_list();
this.enigma_clear_list(reset_frame);
this.http_post('plugin.enigmakeys', params, lock);
};
@ -329,9 +363,11 @@ rcube_webmail.prototype.enigma_list_page = function(page)
};
// Remove list rows
rcube_webmail.prototype.enigma_clear_list = function()
rcube_webmail.prototype.enigma_clear_list = function(reset_frame)
{
this.enigma_loadframe();
if (reset_frame !== false)
this.enigma_loadframe();
if (this.keys_list)
this.keys_list.clear(true);
@ -550,6 +586,9 @@ rcube_webmail.prototype.enigma_find_publickey = function(email)
var lock = rcmail.set_busy(true, 'enigma.importwait'),
post = {_a: 'import', _keys: key};
if (rcmail.env.action == 'plugin.enigmakeys')
post._refresh = 1;
// send request to server
rcmail.http_post('plugin.enigmakeys', post, lock);
}

@ -510,6 +510,10 @@ class enigma_ui
else {
$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation',
array('new' => $result['imported'], 'old' => $result['unchanged']));
if ($result['imported'] && !empty($_POST['_refresh'])) {
$this->rc->output->command('enigma_list', 1, false);
}
}
}
else {
@ -566,20 +570,51 @@ class enigma_ui
$upload = new html_inputfield(array('type' => 'file', 'name' => '_file',
'id' => 'rcmimportfile', 'size' => 30));
$search = new html_inputfield(array('type' => 'text', 'name' => '_search',
'id' => 'rcmimportsearch', 'size' => 30));
$upload_button = new html_inputfield(array(
'type' => 'button',
'value' => $this->rc->gettext('import'),
'class' => 'button',
'onclick' => "return rcmail.command('plugin.enigma-import','',this,event)",
));
$search_button = new html_inputfield(array(
'type' => 'button',
'value' => $this->rc->gettext('search'),
'class' => 'button',
'onclick' => "return rcmail.command('plugin.enigma-import-search','',this,event)",
));
$form = html::p(null,
$upload_form = html::div(null,
rcube::Q($this->enigma->gettext('keyimporttext'), 'show')
. html::br() . html::br() . $upload->show()
. html::br() . html::br() . $upload_button->show()
);
$this->rc->output->add_label('selectimportfile', 'importwait');
$search_form = html::div(null,
rcube::Q($this->enigma->gettext('keyimportsearchtext'), 'show')
. html::br() . html::br() . $search->show()
. html::br() . html::br() . $search_button->show()
);
$form = html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportlabel')) . $upload_form)
. html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportsearchlabel')) . $search_form);
$this->rc->output->add_label('selectimportfile', 'importwait', 'nopubkeyfor', 'nopubkeyforsender',
'encryptnoattachments','encryptedsendialog','searchpubkeyservers', 'importpubkeys',
'encryptpubkeysfound', 'search', 'close', 'import', 'keyid', 'keylength', 'keyexpired',
'keyrevoked', 'keyimportsuccess', 'keyservererror');
$this->rc->output->add_gui_object('importform', $attrib['id']);
$this->rc->output->include_script('publickey.js');
$out = $this->rc->output->form_tag(array(
'action' => $this->rc->url(array('action' => $this->rc->action, 'a' => 'import')),
'method' => 'post',
'action' => $this->rc->url(array('action' => $this->rc->action, 'a' => 'import')),
'method' => 'post',
'enctype' => 'multipart/form-data') + $attrib,
$form);
$form
);
return $out;
}

@ -89,6 +89,8 @@ $labels['keyexportprompt'] = 'Do you want to include secret keys in the saved Op
$labels['onlypubkeys'] = 'Export Public Keys Only';
$labels['withprivkeys'] = 'Export Secret Keys';
$labels['findkey'] = 'Search on key server(s)';
$labels['keyimportlabel'] = 'Import from file';
$labels['keyimportsearchlabel'] = 'Search on key server(s)';
$messages = array();
$messages['sigvalid'] = 'Verified signature from $sender.';
@ -120,6 +122,7 @@ $messages['keyremoveconfirm'] = 'Are you sure, you want to delete selected key(s
$messages['keyremovesuccess'] = 'Key(s) deleted successfully';
$messages['keyremoveerror'] = 'Unable to delete selected key(s).';
$messages['keyimporttext'] = 'You can import private and public key(s) or revocation signatures in ASCII-Armor format.';
$messages['keyimportsearchtext'] = 'You can search for public keys by key identifier, user name or email address and then import them directly.';
$messages['formerror'] = 'Please, fill the form. All fields are required!';
$messages['passwordsdiffer'] = 'Passwords do not match!';

@ -151,6 +151,11 @@ div.enigmascreen
border: 0;
}
#keyimportform fieldset div {
color: #666;
padding: 5px 0px;
}
#keystoolbar
{
position: absolute;

@ -9,10 +9,7 @@
<div id="keyimport-title" class="boxtitle"><roundcube:label name="enigma.importkeys" /></div>
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" />
<p>
<br /><roundcube:button command="plugin.enigma-import" type="input" class="button mainaction" label="import" />
</p>
<roundcube:object name="importform" id="keyimportform" />
</div>
</body>

@ -141,6 +141,12 @@ p.enigmaattachment a {
text-overflow: ellipsis;
}
#keyimportform fieldset div
{
background-color: #eee;
padding: 10px;
}
#keystoolbar
{
position: absolute;

@ -9,11 +9,7 @@
<h1 class="boxtitle"><roundcube:label name="enigma.importkeys" /></h1>
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" />
<br>
<div class="formbuttons">
<roundcube:button command="plugin.enigma-import" type="input" class="button mainaction" label="import" />
</div>
<roundcube:object name="importform" class="propform" id="keyimportform" />
</div>
<roundcube:include file="/includes/footer.html" />

@ -3808,7 +3808,7 @@ function rcube_webmail()
// them into the local Maivelope keyring
this.mailvelope_key_import_dialog = function(candidates, import_handler)
{
var ul = $('<div>').addClass('listing mailvelopekeyimport');
var ul = $('<div>').addClass('listing pgpkeyimport');
$.each(candidates, function(i, keyrec) {
var li = $('<div>').addClass('key');
if (keyrec.revoked) li.addClass('revoked');
@ -3862,8 +3862,8 @@ function rcube_webmail()
ref.get_label('importpubkeys'),
[{
text: ref.get_label('close'),
click: function(){
$(this).dialog('close');
click: function() {
(ref.is_framed() ? parent.$ : $)(this).dialog('close');
}
}]
);

@ -1556,3 +1556,57 @@ table.quota-info td.root {
-moz-box-shadow: 0 0 5px 0 #999;
-o-box-shadow: 0 0 5px 0 #999;
}
/** PGP key import dialog **/
.pgpkeyimport div.key {
position: relative;
margin-bottom: 2px;
padding: 1em 1em 5px;
background-color: #ebebeb;
}
.pgpkeyimport div.key.revoked,
.pgpkeyimport div.key.disabled {
color: #a0a0a0;
}
.pgpkeyimport div.key label {
display: inline-block;
margin-right: 0.5em;
}
.pgpkeyimport div.key label:after {
content: ":";
}
.pgpkeyimport div.key label + a,
.pgpkeyimport div.key label + span {
display: inline-block;
margin-right: 2em;
white-space: nowrap;
}
.pgpkeyimport div.key label + a {
font-weight: bold;
}
.pgpkeyimport ul.uids {
margin: 5px 1em 0 1em;
padding: 0;
}
.pgpkeyimport li.uid {
border: 0;
padding: 2px;
}
.pgpkeyimport div.key input.button.importkey {
position: absolute;
top: 0.8em;
right: 0.8em;
padding: 2px 6px;
}
.pgpkeyimport div.key input.button[disabled] {
display: none;
}

@ -1736,56 +1736,3 @@ input.from_address
top: 45px;
position: absolute;
}
.mailvelopekeyimport div.key {
position: relative;
margin-bottom: 2px;
padding: 1em 1em 5px;
background-color: #ebebeb;
}
.mailvelopekeyimport div.key.revoked,
.mailvelopekeyimport div.key.disabled {
color: #a0a0a0;
}
.mailvelopekeyimport div.key label {
display: inline-block;
margin-right: 0.5em;
}
.mailvelopekeyimport div.key label:after {
content: ":";
}
.mailvelopekeyimport div.key label + a,
.mailvelopekeyimport div.key label + span {
display: inline-block;
margin-right: 2em;
white-space: nowrap;
}
.mailvelopekeyimport div.key label + a {
font-weight: bold;
}
.mailvelopekeyimport ul.uids {
margin: 5px 1em 0 1em;
padding: 0;
}
.mailvelopekeyimport li.uid {
border: 0;
padding: 2px;
}
.mailvelopekeyimport div.key input.button.importkey {
position: absolute;
top: 0.8em;
right: 0.8em;
padding: 2px 6px;
}
.mailvelopekeyimport div.key input.button[disabled] {
display: none;
}

@ -1410,56 +1410,3 @@ div.message-partheaders .headers-table td.header {
#uploadform form div {
margin: 4px 0;
}
.mailvelopekeyimport div.key {
position: relative;
margin-bottom: 2px;
padding: 1em;
background-color: #ebebeb;
}
.mailvelopekeyimport div.key.revoked,
.mailvelopekeyimport div.key.disabled {
color: #a0a0a0;
}
.mailvelopekeyimport div.key label {
display: inline-block;
margin-right: 0.5em;
}
.mailvelopekeyimport div.key label:after {
content: ":";
}
.mailvelopekeyimport div.key label + a,
.mailvelopekeyimport div.key label + span {
display: inline-block;
margin-right: 2em;
white-space: nowrap;
}
.mailvelopekeyimport div.key label + a {
font-weight: bold;
}
.mailvelopekeyimport ul.uids {
margin: 1em 0 0 0;
padding: 0;
}
.mailvelopekeyimport li.uid {
border: 0;
padding: 0.3em;
}
.mailvelopekeyimport div.key input.button.importkey {
position: absolute;
top: 0.8em;
right: 0.8em;
padding: 4px 6px;
}
.mailvelopekeyimport div.key input.button[disabled] {
display: none;
}

@ -3160,3 +3160,57 @@ _:not(), _:-moz-handler-blocked, .mozilla .mce-btn-small i {
box-shadow: none;
outline: none;
}
/** PGP Key import dialog **/
.pgpkeyimport div.key {
position: relative;
margin-bottom: 2px;
padding: 1em;
background-color: #ebebeb;
}
.pgpkeyimport div.key.revoked,
.pgpkeyimport div.key.disabled {
color: #a0a0a0;
}
.pgpkeyimport div.key label {
display: inline-block;
margin-right: 0.5em;
}
.pgpkeyimport div.key label:after {
content: ":";
}
.pgpkeyimport div.key label + a,
.pgpkeyimport div.key label + span {
display: inline-block;
margin-right: 2em;
white-space: nowrap;
}
.pgpkeyimport div.key label + a {
font-weight: bold;
}
.pgpkeyimport ul.uids {
margin: 1em 0 0 0;
padding: 0;
}
.pgpkeyimport li.uid {
border: 0;
padding: 0.3em;
}
.pgpkeyimport div.key input.button.importkey {
position: absolute;
top: 0.8em;
right: 0.8em;
padding: 4px 6px;
}
.pgpkeyimport div.key input.button[disabled] {
display: none;
}

Loading…
Cancel
Save