diff --git a/program/js/app.js b/program/js/app.js index 26a6f6fb7..4ff79be89 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -511,6 +511,8 @@ function rcube_webmail() // initialize HTML editor this.editor_init(this.env.editor_config, 'rcmfd_signature'); + + this.check_mailvelope(this.env.action); } else if (this.env.action == 'folders') { this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', true); @@ -3638,6 +3640,8 @@ function rcube_webmail() if (args.ret && args.action == 'toggle-editor') ref.enable_command('compose-encrypted', !args.props.html); }); + } else if (action == 'edit-identity') { + ref.mailvelope_identity_keygen(); } }; @@ -4000,6 +4004,127 @@ function rcube_webmail() }; + // enable key management for identity + this.mailvelope_identity_keygen = function() + { + var container = $(this.gui_objects.editform).find('.identity-encryption').first(); + var identity_email = $.trim($(this.gui_objects.editform).find('.ff_email').val()); + if (!container.length || !identity_email || !this.mailvelope_keyring.createKeyGenContainer) + return; + + var key_fingerprint; + this.mailvelope_keyring.validKeyForAddress([identity_email]) + .then(function(keys) { + var private_keys = []; + + if (keys && keys[identity_email] && Array.isArray(keys[identity_email].keys)) { + var checks = []; + for (var j=0; j < keys[identity_email].keys.length; j++) { + checks.push((function(key) { + return ref.mailvelope_keyring.hasPrivateKey(key.fingerprint) + .then(function(found) { + if (found) { + private_keys.push(key); + } + }); + })(keys[identity_email].keys[j])); + } + return Promise.all(checks) + .then(function() { + return private_keys; + }); + } + + return private_keys; + }).then(function(private_keys) { + var content = container.find('.identity-encryption-block').empty(); + if (private_keys && private_keys.length) { + // show private key information + $('
').text(ref.get_label('encryptionprivkeysinmailvelope').replace('$nr', private_keys.length)).appendTo(content); + var ul = $('
').text(ref.get_label('encryptionnoprivkeysinmailvelope')).appendTo(content); + } + + // show button to create a new key + $('') + .attr('type', 'button') + .addClass('button create') + .text(ref.get_label('encryptioncreatekey')) + .appendTo(content) + .on('click', function() { ref.mailvelope_show_keygen_container(content, identity_email); }); + $('') + .attr('type', 'button') + .addClass('button settings') + .text(ref.get_label('openmailvelopesettings')) + .appendTo(content) + .on('click', function() { ref.mailvelope_keyring.openSettings(); }); + + container.show(); + }) + .catch(function(err) { + console.error('Mailvelope keyring error', err); + }) + }; + + // start pgp key generation using Mailvelope + this.mailvelope_show_keygen_container = function(container, identity_email) + { + var cid = new Date().getTime(); + var user_id = {email: identity_email, fullName: $.trim($(ref.gui_objects.editform).find('.ff_name').val())}; + var options = {userIds: [user_id], keySize: 4096}; + + $('').attr('id', 'mailvelope-keygen-container-' + cid) + .css({height: '245px', marginBottom: '10px'}) + .appendTo(container.empty()); + + this.mailvelope_keyring.createKeyGenContainer('#mailvelope-keygen-container-' + cid, options) + .then(function(generator) { + if (generator instanceof Error) { + throw generator; + } + + // append button to start key generation + $('') + .attr('type', 'button') + .addClass('button mainaction generate') + .text(ref.get_label('generate')) + .appendTo(container) + .on('click', function() { + var btn = $(this).prop('disabled', true); + generator.generate() + .then(function(result) { + if (typeof result === 'string' && result.indexOf('BEGIN PGP') > 0) { + ref.display_message(ref.get_label('keypaircreatesuccess').replace('$identity', identity_email), 'confirmation'); + // reset keygen view + ref.mailvelope_identity_keygen(); + } + }) + .catch(function(err) { + debugger; + ref.display_message(err.message || 'errortitle', 'error'); + btn.prop('disabled', false); + }); + }); + + $('') + .attr('type', 'button') + .addClass('button cancel') + .text(ref.get_label('cancel')) + .appendTo(container) + .on('click', function() { ref.mailvelope_identity_keygen(); }); + }) + .catch(function(err) { + ref.display_message('errortitle', 'error'); + // start over + ref.mailvelope_identity_keygen(); + }); + }; /*********************************************************/ /********* mailbox folders methods *********/ diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 543fd4817..cd778df99 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -482,6 +482,7 @@ $labels['manageidentities'] = 'Manage identities'; $labels['newidentity'] = 'Create new identity'; $labels['addidentity'] = 'Add identity'; $labels['editidentity'] = 'Edit identity'; +$labels['identityencryption'] = 'Encryption'; $labels['preferhtml'] = 'Display HTML'; $labels['defaultcharset'] = 'Default Character Set'; @@ -619,6 +620,12 @@ $labels['dualuselabel'] = 'Can contain only'; $labels['dualusemail'] = 'messages'; $labels['dualusefolder'] = 'folders'; +$labels['generate'] = 'Generate'; +$labels['encryptioncreatekey'] = 'Create a new key pair'; +$labels['openmailvelopesettings'] = 'Open Mailvelope Settings'; +$labels['encryptionprivkeysinmailvelope'] = 'You have $nr matching private keys stored in your Mailvelope keyring:'; +$labels['encryptionnoprivkeysinmailvelope'] = 'This sender identity doesn\'t yet have a PGP private key stored in your Mailvelope extension. Would you like to create one in order to enable encrypted messaging?'; + $labels['sortby'] = 'Sort by'; $labels['sortasc'] = 'Sort ascending'; $labels['sortdesc'] = 'Sort descending'; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index 68af7d6d4..7d98db5c2 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -221,3 +221,4 @@ $messages['siginserted'] = 'Signature inserted successfully.'; $messages['responseinserted'] = 'Response inserted successfully.'; $messages['listempty'] = 'The list is empty.'; $messages['listusebutton'] = 'Use the Create button to add a new record.'; +$messages['keypaircreatesuccess'] = 'A new key pair has been successfully created for $identity.'; diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 6882cdd00..ee22b75f2 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -52,7 +52,9 @@ else { $OUTPUT->include_script('list.js'); $OUTPUT->add_handler('identityform', 'rcube_identity_form'); $OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); -$OUTPUT->add_label('deleteidentityconfirm', 'uploading'); +$OUTPUT->add_label('deleteidentityconfirm', 'uploading', 'generate', + 'encryptioncreatekey', 'openmailvelopesettings', 'encryptionprivkeysinmailvelope', + 'encryptionnoprivkeysinmailvelope', 'keypaircreatesuccess'); $OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add-identity' ? 'addidentity' : 'editidentity'))); @@ -97,7 +99,12 @@ function rcube_identity_form($attrib) 'html_signature' => array('type' => 'checkbox', 'label' => $RCMAIL->gettext('htmlsignature'), 'onclick' => 'return rcmail.command(\'toggle-editor\', {id: \'rcmfd_signature\', html: this.checked}, \'\', event)'), - )) + )), + 'encryption' => array( + 'name' => $RCMAIL->gettext('identityencryption'), + 'attrs' => array('class' => 'identity-encryption', 'style' => 'display:none'), + 'content' => html::div('identity-encryption-block', '') + ) ); // Enable TinyMCE editor @@ -173,7 +180,7 @@ function rcube_identity_form($attrib) } $content = html::tag('legend', null, rcube::Q($fieldset['name'])) . $content; - $out .= html::tag('fieldset', null, $content) . "\n"; + $out .= html::tag('fieldset', $fieldset['attrs'], $content) . "\n"; } $out .= $form_end; diff --git a/skins/larry/settings.css b/skins/larry/settings.css index 62eef92c5..c48a2af48 100644 --- a/skins/larry/settings.css +++ b/skins/larry/settings.css @@ -78,6 +78,21 @@ background-position: -24px -1137px; } +#preferences-details .identity-encryption-block { + background-color: #eee; + padding: 8px 10px; +} + +#preferences-details .identity-encryption-block ul.keylist { + list-style: none; + margin: 8px 0 12px 0; +} + +#preferences-details .identity-encryption-block ul.keylist { + display: block; + padding: 4px 10px 4px 0; +} + #sections-table tbody td, #sections-table .listitem span, #settings-sections .listitem a,