Enigma: Implemented messages signing and encrypting
1 files added
17 files modified
| | |
| | | |
| | | Plugin Status: |
| | | |
| | | + PGP: signed messages verification |
| | | + PGP: signatures verification |
| | | + PGP: messages decryption |
| | | + PGP: Sending of encrypted/signed messages |
| | | + PGP: keys management UI (keys import and delete) |
| | | + Handling of PGP keys attached to incoming messages |
| | | |
| | | TODO (must have): |
| | | |
| | | - Fix issues with enabled messages_cache |
| | | - PGP: Sending of encrypted/signed messages |
| | | - Per-Identity settings (including keys/certs) |
| | | - Test/Make working with gnupg-2.x |
| | | - PGP: Handling of signed inside encrypted message |
| | | - Make working with gnupg-2.x |
| | | - Keys export to file |
| | | - Disable Reply/Forward options when viewing encrypted messages |
| | | until they are decrypted successfully |
| | | - Handling of replying/forwarding of encrypted messages |
| | | - Handling of replying/forwarding of encrypted/signed messages |
| | | - Add composer.json file |
| | | - Performance improvements: |
| | | - cache decrypted message key id in cache so we can skip |
| | | decryption if we have no password in session |
| | | - cache sig verification status to not verify on every msg preview (optional) |
| | | - cache decrypted message key id so we can skip decryption if we have no password in session |
| | | - cache (last or successful only?) sig verification status to not verify on every msg preview (optional) |
| | | |
| | | TODO (later): |
| | | |
| | |
| | | - Mark keys as trusted/untrasted, display appropriate message in verify/decrypt status |
| | | - User-preferences to disable signature verification, decrypting, encrypting or all enigma features |
| | | - Change attachment icon on messages list for encrypted messages (like vcard_attachment plugin does) |
| | | - Support for multi-server installations (store keys in sql database?) |
| | | - Per-Identity settings (including keys/certs) |
| | | |
| | | - S/MIME: Certs generation |
| | | - S/MIME: Certs management |
| | |
| | | // Keys directory for all users. Default 'enigma/home'. |
| | | // Must be writeable by PHP process |
| | | $config['enigma_pgp_homedir'] = null; |
| | | |
| | | // Enable signing all messages by default |
| | | $config['enigma_sign_all'] = false; |
| | | |
| | | // Enable encrypting all messages by default |
| | | $config['enigma_encrypt_all'] = false; |
| | |
| | | } |
| | | else if (rcmail.env.task == 'mail') { |
| | | if (rcmail.env.action == 'compose') { |
| | | rcmail.addEventListener('beforesend', function(props) { rcmail.enigma_beforesend_handler(props); }) |
| | | .addEventListener('beforesavedraft', function(props) { rcmail.enigma_beforesavedraft_handler(props); }); |
| | | |
| | | $('input,label', $('#enigmamenu')).mouseup(function(e) { |
| | | // don't close the menu on mouse click inside |
| | | e.stopPropagation(); |
| | |
| | | list.insert_row(row); |
| | | } |
| | | |
| | | |
| | | /*********************************************************/ |
| | | /********* Enigma Message methods *********/ |
| | | /*********************************************************/ |
| | | |
| | | // handle message send/save action |
| | | rcube_webmail.prototype.enigma_beforesend_handler = function(props) |
| | | { |
| | | this.env.last_action = 'send'; |
| | | this.enigma_compose_handler(props); |
| | | } |
| | | |
| | | rcube_webmail.prototype.enigma_beforesavedraft_handler = function(props) |
| | | { |
| | | this.env.last_action = 'savedraft'; |
| | | this.enigma_compose_handler(props); |
| | | } |
| | | |
| | | rcube_webmail.prototype.enigma_compose_handler = function(props) |
| | | { |
| | | var form = this.gui_objects.messageform; |
| | | |
| | | // copy inputs from enigma menu to the form |
| | | $('#enigmamenu input').each(function() { |
| | | var id = this.id + '_cpy', input = $('#' + id); |
| | | |
| | | if (!input.length) { |
| | | input = $(this).clone(); |
| | | input.prop({id: id, type: 'hidden'}).appendTo(form); |
| | | } |
| | | |
| | | input.val(this.checked ? '1' : ''); |
| | | }); |
| | | |
| | | // disable signing when saving drafts |
| | | if (this.env.last_action == 'savedraft') { |
| | | $('input[name="_enigma_sign"]', form).val(0); |
| | | } |
| | | } |
| | | |
| | | // Import attached keys/certs file |
| | | rcube_webmail.prototype.enigma_import_attachment = function(mime_id) |
| | |
| | | return false; |
| | | } |
| | | |
| | | // password request popup |
| | | rcube_webmail.prototype.enigma_password_request = function(data) |
| | | { |
| | | if (!data || !data.keyid) { |
| | |
| | | .appendTo(myprompt); |
| | | |
| | | data.key = data.keyid; |
| | | data.keyid = data.keyid.substr(0, 8); |
| | | if (data.keyid.length > 8) |
| | | data.keyid = data.keyid.substr(data.keyid.length - 8); |
| | | |
| | | $.each(['keyid', 'user'], function() { |
| | | msg = msg.replace('$' + this, data[this]); |
| | |
| | | } |
| | | } |
| | | |
| | | // submit entered password |
| | | rcube_webmail.prototype.enigma_password_submit = function(keyid, password) |
| | | { |
| | | if (this.env.action == 'compose') { |
| | | return this.enigma_password_compose_submit(keyid, password); |
| | | } |
| | | |
| | | // message preview |
| | | var form = $('<form>').attr({method: 'post', action: location.href, style: 'display:none'}) |
| | | .append($('<input>').attr({type: 'hidden', name: '_keyid', value: keyid})) |
| | | .append($('<input>').attr({type: 'hidden', name: '_passwd', value: password})) |
| | |
| | | |
| | | form.submit(); |
| | | } |
| | | |
| | | // submit entered password - in mail compose page |
| | | rcube_webmail.prototype.enigma_password_compose_submit = function(keyid, password) |
| | | { |
| | | var form = this.gui_objects.messageform; |
| | | |
| | | if (!$('input[name="_keyid"]', form).length) { |
| | | $(form).append($('<input>').attr({type: 'hidden', name: '_keyid', value: keyid})) |
| | | .append($('<input>').attr({type: 'hidden', name: '_passwd', value: password})); |
| | | } |
| | | else { |
| | | $('input[name="_keyid"]', form).val(keyid); |
| | | $('input[name="_passwd"]', form).val(password); |
| | | } |
| | | |
| | | this.submit_messageform(this.env.last_action == 'savedraft'); |
| | | } |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | Enigma Plugin for Roundcube | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | $this->rc = rcube::get_instance(); |
| | | |
| | | if ($this->rc->task == 'mail') { |
| | | $section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET); |
| | | |
| | | // message parse/display hooks |
| | | $this->add_hook('message_part_structure', array($this, 'part_structure')); |
| | | $this->add_hook('message_part_body', array($this, 'part_body')); |
| | |
| | | // message composing |
| | | else if ($this->rc->action == 'compose') { |
| | | $this->load_ui(); |
| | | $this->ui->init($section); |
| | | $this->ui->init(); |
| | | } |
| | | // message sending (and draft storing) |
| | | else if ($this->rc->action == 'sendmail') { |
| | | //$this->add_hook('outgoing_message_body', array($this, 'msg_encode')); |
| | | //$this->add_hook('outgoing_message_body', array($this, 'msg_sign')); |
| | | else if ($this->rc->action == 'send') { |
| | | $this->add_hook('message_ready', array($this, 'message_ready')); |
| | | } |
| | | |
| | | $this->password_handler(); |
| | |
| | | else if ($this->rc->task == 'settings') { |
| | | // add hooks for Enigma settings |
| | | $this->add_hook('settings_actions', array($this, 'settings_actions')); |
| | | // $this->add_hook('preferences_list', array($this, 'preferences_list')); |
| | | // $this->add_hook('preferences_save', array($this, 'preferences_save')); |
| | | $this->add_hook('preferences_sections_list', array($this, 'preferences_sections_list')); |
| | | $this->add_hook('preferences_list', array($this, 'preferences_list')); |
| | | $this->add_hook('preferences_save', array($this, 'preferences_save')); |
| | | |
| | | // register handler for keys/certs management |
| | | // $this->register_action('plugin.enigma', array($this, 'preferences_ui')); |
| | | $this->register_action('plugin.enigmakeys', array($this, 'preferences_ui')); |
| | | $this->register_action('plugin.enigmacerts', array($this, 'preferences_ui')); |
| | | // $this->register_action('plugin.enigmacerts', array($this, 'preferences_ui')); |
| | | |
| | | $this->load_ui(); |
| | | $this->ui->add_css(); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Handler for preferences_sections_list hook. |
| | | * Adds Encryption settings section into preferences sections list. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function preferences_sections_list($p) |
| | | { |
| | | $p['list']['enigma'] = array( |
| | | 'id' => 'enigma', 'section' => $this->gettext('encryption'), |
| | | ); |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for preferences_list hook. |
| | | * Adds options blocks into Enigma settings sections in Preferences. |
| | | * |
| | |
| | | */ |
| | | function preferences_list($p) |
| | | { |
| | | /* |
| | | if ($p['section'] == 'enigmasettings') { |
| | | // This makes that section is not removed from the list |
| | | $p['blocks']['dummy']['options']['dummy'] = array(); |
| | | if ($p['section'] != 'enigma') { |
| | | return $p; |
| | | } |
| | | */ |
| | | |
| | | $no_override = array_flip((array)$this->rc->config->get('dont_override')); |
| | | |
| | | $p['blocks']['main']['name'] = $this->gettext('mainoptions'); |
| | | |
| | | if (!isset($no_override['enigma_sign_all'])) { |
| | | if (!$p['current']) { |
| | | $p['blocks']['main']['content'] = true; |
| | | return $p; |
| | | } |
| | | |
| | | $field_id = 'rcmfd_enigma_sign_all'; |
| | | $input = new html_checkbox(array( |
| | | 'name' => '_enigma_sign_all', |
| | | 'id' => $field_id, |
| | | 'value' => 1, |
| | | )); |
| | | |
| | | $p['blocks']['main']['options']['enigma_sign_all'] = array( |
| | | 'title' => html::label($field_id, $this->gettext('signdefault')), |
| | | 'content' => $input->show($this->rc->config->get('enigma_sign_all') ? 1 : 0), |
| | | ); |
| | | } |
| | | |
| | | if (!isset($no_override['enigma_encrypt_all'])) { |
| | | if (!$p['current']) { |
| | | $p['blocks']['main']['content'] = true; |
| | | return $p; |
| | | } |
| | | |
| | | $field_id = 'rcmfd_enigma_encrypt_all'; |
| | | $input = new html_checkbox(array( |
| | | 'name' => '_enigma_encrypt_all', |
| | | 'id' => $field_id, |
| | | 'value' => 1, |
| | | )); |
| | | |
| | | $p['blocks']['main']['options']['enigma_encrypt_all'] = array( |
| | | 'title' => html::label($field_id, $this->gettext('encryptdefault')), |
| | | 'content' => $input->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0), |
| | | ); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | |
| | | */ |
| | | function preferences_save($p) |
| | | { |
| | | /* |
| | | if ($p['section'] == 'enigmasettings') { |
| | | $a['prefs'] = array( |
| | | 'dummy' => rcube_utils::get_input_value('_dummy', rcube_utils::INPUT_POST), |
| | | if ($p['section'] == 'enigma') { |
| | | $p['prefs'] = array( |
| | | 'enigma_sign_all' => intval(rcube_utils::get_input_value('_enigma_sign_all', rcube_utils::INPUT_POST)), |
| | | 'enigma_encrypt_all' => intval(rcube_utils::get_input_value('_enigma_encrypt_all', rcube_utils::INPUT_POST)), |
| | | ); |
| | | } |
| | | */ |
| | | |
| | | return $p; |
| | | } |
| | | |
| | |
| | | function password_handler() |
| | | { |
| | | $this->load_engine(); |
| | | |
| | | $this->engine->password_handler(); |
| | | } |
| | | |
| | | /** |
| | | * Handle message_ready hook (encryption/signing) |
| | | */ |
| | | function message_ready($p) |
| | | { |
| | | $this->load_ui(); |
| | | |
| | | return $this->ui->message_ready($p); |
| | | } |
| | | |
| | | /** |
| | | * Handler for refresh hook. |
| | | */ |
| | | function refresh($p) |
| | |
| | | <?php |
| | | |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Abstract driver for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | /** |
| | | * Signing. |
| | | */ |
| | | abstract function sign($text, $key, $passwd); |
| | | abstract function sign($text, $key, $passwd, $mode = null); |
| | | |
| | | /** |
| | | * Signature verification. |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | GnuPG (PGP) driver for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | private $gpg; |
| | | private $homedir; |
| | | private $user; |
| | | |
| | | |
| | | function __construct($user) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Encrypt a message |
| | | * |
| | | * @param string The message |
| | | * @param array List of keys |
| | | */ |
| | | function encrypt($text, $keys) |
| | | { |
| | | /* |
| | | foreach ($keys as $key) { |
| | | $this->gpg->addEncryptKey($key); |
| | | try { |
| | | foreach ($keys as $key) { |
| | | $this->gpg->addEncryptKey($key); |
| | | } |
| | | |
| | | $dec = $this->gpg->encrypt($text, true); |
| | | return $dec; |
| | | } |
| | | $enc = $this->gpg->encrypt($text); |
| | | return $enc; |
| | | */ |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Register private keys and passwords |
| | | * Decrypt a message |
| | | * |
| | | * @param string Encrypted message |
| | | * @param array List of key-password mapping |
| | | */ |
| | | function decrypt($text, $keys = array()) |
| | | { |
| | | foreach ($keys as $key => $password) { |
| | | $this->gpg->addDecryptKey($key, $password); |
| | | } |
| | | |
| | | try { |
| | | foreach ($keys as $key => $password) { |
| | | $this->gpg->addDecryptKey($key, $password); |
| | | } |
| | | |
| | | $dec = $this->gpg->decrypt($text); |
| | | return $dec; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | function sign($text, $key, $passwd) |
| | | function sign($text, $key, $passwd, $mode = null) |
| | | { |
| | | /* |
| | | $this->gpg->addSignKey($key, $passwd); |
| | | $signed = $this->gpg->sign($text, Crypt_GPG::SIGN_MODE_DETACHED); |
| | | return $signed; |
| | | */ |
| | | try { |
| | | $this->gpg->addSignKey($key, $passwd); |
| | | return $this->gpg->sign($text, $mode, CRYPT_GPG::ARMOR_ASCII, true); |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | function verify($text, $signature) |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | S/MIME driver for the Enigma Plugin | |
| | | | S/MIME driver for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | { |
| | | } |
| | | |
| | | function sign($text, $key, $passwd) |
| | | function sign($text, $key, $passwd, $mode = null) |
| | | { |
| | | } |
| | | |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | Engine of the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | |
| | | */ |
| | | |
| | | /* |
| | |
| | | public $signed_parts = array(); |
| | | |
| | | const PASSWORD_TIME = 120; |
| | | |
| | | const SIGN_MODE_BODY = 1; |
| | | const SIGN_MODE_SEPARATE = 2; |
| | | const SIGN_MODE_MIME = 3; |
| | | |
| | | const ENCRYPT_MODE_BODY = 1; |
| | | const ENCRYPT_MODE_MIME = 2; |
| | | |
| | | |
| | | /** |
| | |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: ".$result->getMessage() |
| | | ), true, true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for message signing |
| | | * |
| | | * @param Mail_mime Original message |
| | | * @param int Encryption mode |
| | | * |
| | | * @return enigma_error On error returns error object |
| | | */ |
| | | function sign_message(&$message, $mode = null) |
| | | { |
| | | $mime = new enigma_mime_message($message, enigma_mime_message::PGP_SIGNED); |
| | | $from = $mime->getFromAddress(); |
| | | |
| | | // find private key |
| | | $key = $this->find_key($from, true); |
| | | |
| | | if (empty($key)) { |
| | | return new enigma_error(enigma_error::E_KEYNOTFOUND); |
| | | } |
| | | |
| | | // check if we have password for this key |
| | | $passwords = $this->get_passwords(); |
| | | $pass = $passwords[$key->id]; |
| | | |
| | | if ($pass === null) { |
| | | // ask for password |
| | | $error = array('missing' => array($key->id => $key->name)); |
| | | return new enigma_error(enigma_error::E_BADPASS, '', $error); |
| | | } |
| | | |
| | | // select mode |
| | | switch ($mode) { |
| | | case self::SIGN_MODE_BODY: |
| | | $pgp_mode = Crypt_GPG::SIGN_MODE_CLEAR; |
| | | break; |
| | | |
| | | case self::SIGN_MODE_MIME: |
| | | $pgp_mode = Crypt_GPG::SIGN_MODE_DETACHED; |
| | | break; |
| | | /* |
| | | case self::SIGN_MODE_SEPARATE: |
| | | $pgp_mode = Crypt_GPG::SIGN_MODE_NORMAL; |
| | | break; |
| | | */ |
| | | default: |
| | | if ($mime->isMultipart()) { |
| | | $pgp_mode = Crypt_GPG::SIGN_MODE_DETACHED; |
| | | } |
| | | else { |
| | | $pgp_mode = Crypt_GPG::SIGN_MODE_CLEAR; |
| | | } |
| | | } |
| | | |
| | | // get message body |
| | | if ($pgp_mode == Crypt_GPG::SIGN_MODE_CLEAR) { |
| | | // in this mode we'll replace text part |
| | | // with the one containing signature |
| | | $body = $message->getTXTBody(); |
| | | } |
| | | else { |
| | | // here we'll build PGP/MIME message |
| | | $body = $mime->getOrigBody(); |
| | | } |
| | | |
| | | // sign the body |
| | | $result = $this->pgp_sign($body, $key->id, $pass, $pgp_mode); |
| | | |
| | | if ($result !== true) { |
| | | if ($result->getCode() == enigma_error::E_BADPASS) { |
| | | // ask for password |
| | | $error = array('missing' => array($key->id => $key->name)); |
| | | return new enigma_error(enigma_error::E_BADPASS, '', $error); |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | // replace message body |
| | | if ($pgp_mode == Crypt_GPG::SIGN_MODE_CLEAR) { |
| | | $message->setTXTBody($body); |
| | | } |
| | | else { |
| | | $mime->addPGPSignature($body); |
| | | $message = $mime; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for message encryption |
| | | * |
| | | * @param Mail_mime Original message |
| | | * @param int Encryption mode |
| | | * @param bool Is draft-save action - use only sender's key for encryption |
| | | * |
| | | * @return enigma_error On error returns error object |
| | | */ |
| | | function encrypt_message(&$message, $mode = null, $is_draft = false) |
| | | { |
| | | $mime = new enigma_mime_message($message, enigma_mime_message::PGP_ENCRYPTED); |
| | | |
| | | // always use sender's key |
| | | $recipients = array($mime->getFromAddress()); |
| | | |
| | | // if it's not a draft we add all recipients' keys |
| | | if (!$is_draft) { |
| | | $recipients = array_merge($recipients, $mime->getRecipients()); |
| | | } |
| | | |
| | | if (empty($recipients)) { |
| | | return new enigma_error(enigma_error::E_KEYNOTFOUND); |
| | | } |
| | | |
| | | $recipients = array_unique($recipients); |
| | | |
| | | // find recipient public keys |
| | | foreach ((array) $recipients as $email) { |
| | | $key = $this->find_key($email); |
| | | |
| | | if (empty($key)) { |
| | | return new enigma_error(enigma_error::E_KEYNOTFOUND, '', array( |
| | | 'missing' => $email |
| | | )); |
| | | } |
| | | |
| | | $keys[] = $key->id; |
| | | } |
| | | |
| | | // select mode |
| | | switch ($mode) { |
| | | case self::ENCRYPT_MODE_BODY: |
| | | $encrypt_mode = $mode; |
| | | break; |
| | | |
| | | case self::ENCRYPT_MODE_MIME: |
| | | $encrypt_mode = $mode; |
| | | break; |
| | | |
| | | default: |
| | | $encrypt_mode = $mime->isMultipart() ? self::ENCRYPT_MODE_MIME : self::ENCRYPT_MODE_BODY; |
| | | } |
| | | |
| | | // get message body |
| | | if ($encrypt_mode == self::ENCRYPT_MODE_BODY) { |
| | | // in this mode we'll replace text part |
| | | // with the one containing encrypted message |
| | | $body = $message->getTXTBody(); |
| | | } |
| | | else { |
| | | // here we'll build PGP/MIME message |
| | | $body = $mime->getOrigBody(); |
| | | } |
| | | |
| | | // sign the body |
| | | $result = $this->pgp_encrypt($body, $keys); |
| | | |
| | | if ($result !== true) { |
| | | return $result; |
| | | } |
| | | |
| | | // replace message body |
| | | if ($encrypt_mode == self::ENCRYPT_MODE_BODY) { |
| | | $message->setTXTBody($body); |
| | | } |
| | | else { |
| | | $mime->setPGPEncryptedBody($body); |
| | | $message = $mime; |
| | | } |
| | | } |
| | | |
| | |
| | | private function pgp_verify(&$msg_body, $sig_body=null) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | // @TODO: caching of verification result |
| | | $sig = $this->pgp_driver->verify($msg_body, $sig_body); |
| | | |
| | | if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) |
| | |
| | | private function pgp_decrypt(&$msg_body) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | // @TODO: caching of verification result |
| | | $keys = $this->get_passwords(); |
| | | $result = $this->pgp_driver->decrypt($msg_body, $keys); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | $err_code = $result->getCode(); |
| | | if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) |
| | | rcube::raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | return $result; |
| | | } |
| | | |
| | | $msg_body = $result; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * PGP message signing |
| | | * |
| | | * @param mixed Message body |
| | | * @param string Key ID |
| | | * @param string Key passphrase |
| | | * @param int Signing mode |
| | | * |
| | | * @return mixed True or enigma_error |
| | | */ |
| | | private function pgp_sign(&$msg_body, $keyid, $password, $mode = null) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | $result = $this->pgp_driver->sign($msg_body, $keyid, $password, $mode); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | $err_code = $result->getCode(); |
| | | if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) |
| | | rcube::raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | return $result; |
| | | } |
| | | |
| | | $msg_body = $result; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * PGP message encrypting |
| | | * |
| | | * @param mixed Message body |
| | | * @param array Keys |
| | | * |
| | | * @return mixed True or enigma_error |
| | | */ |
| | | private function pgp_encrypt(&$msg_body, $keys) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | $result = $this->pgp_driver->encrypt($msg_body, $keys); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | $err_code = $result->getCode(); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Find PGP private/public key |
| | | * |
| | | * @param string E-mail address |
| | | * @param bool Need a key for signing? |
| | | * |
| | | * @return enigma_key The key |
| | | */ |
| | | function find_key($email, $can_sign = false) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $result = $this->pgp_driver->list_keys($email); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | rcube::raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | |
| | | return; |
| | | } |
| | | |
| | | $mode = $can_sign ? enigma_key::CAN_SIGN : enigma_key::CAN_ENCRYPT; |
| | | |
| | | // check key validity and type |
| | | foreach ($result as $key) { |
| | | if ($keyid = $key->find_subkey($email, $mode)) { |
| | | return $key; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * PGP key details. |
| | | * |
| | | * @param mixed Key ID |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | Error class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | private $data = array(); |
| | | |
| | | // error codes |
| | | const E_OK = 0; |
| | | const E_INTERNAL = 1; |
| | | const E_NODATA = 2; |
| | | const E_OK = 0; |
| | | const E_INTERNAL = 1; |
| | | const E_NODATA = 2; |
| | | const E_KEYNOTFOUND = 3; |
| | | const E_DELKEY = 4; |
| | | const E_BADPASS = 5; |
| | | const E_EXPIRED = 6; |
| | | const E_UNVERIFIED = 7; |
| | | const E_DELKEY = 4; |
| | | const E_BADPASS = 5; |
| | | const E_EXPIRED = 6; |
| | | const E_UNVERIFIED = 7; |
| | | |
| | | |
| | | function __construct($code = null, $message = '', $data = array()) |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | Key class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | const TYPE_UNKNOWN = 0; |
| | | const TYPE_KEYPAIR = 1; |
| | | const TYPE_PUBLIC = 2; |
| | | |
| | | const CAN_SIGN = 1; |
| | | const CAN_ENCRYPT = 2; |
| | | |
| | | /** |
| | | * Keys list sorting callback for usort() |
| | |
| | | } |
| | | |
| | | /** |
| | | * Get key ID by user email |
| | | */ |
| | | function find_subkey($email, $mode) |
| | | { |
| | | $now = time(); |
| | | |
| | | foreach ($this->users as $user) { |
| | | if ($user->email === $email && $user->valid && !$user->revoked) { |
| | | foreach ($this->subkeys as $subkey) { |
| | | if (!$subkey->revoked && (!$subkey->expires || $subkey->expires > $now)) { |
| | | if (($mode == self::CAN_ENCRYPT && $subkey->can_encrypt) |
| | | || ($mode == self::CAN_SIGN && $subkey->has_private) |
| | | ) { |
| | | return $subkey; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Converts long ID or Fingerprint to short ID |
| | | * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID |
| | | * |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Mail_mime wrapper for the Enigma Plugin | |
| | | | | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_mime_message extends Mail_mime |
| | | { |
| | | const PGP_SIGNED = 1; |
| | | const PGP_ENCRYPTED = 2; |
| | | |
| | | protected $_type; |
| | | protected $_message; |
| | | protected $_body; |
| | | protected $_signature; |
| | | protected $_encrypted; |
| | | |
| | | |
| | | /** |
| | | * Object constructor |
| | | * |
| | | * @param Mail_mime Original message |
| | | * @param int Output message type |
| | | */ |
| | | function __construct($message, $type) |
| | | { |
| | | $this->_message = $message; |
| | | $this->_type = $type; |
| | | |
| | | // clone parameters |
| | | foreach (array_keys($this->_build_params) as $param) { |
| | | $this->_build_params[$param] = $message->getParam($param); |
| | | } |
| | | |
| | | // clone headers |
| | | $this->_headers = $message->_headers; |
| | | |
| | | /* |
| | | if ($message->getParam('delay_file_io')) { |
| | | // use common temp dir |
| | | $temp_dir = $this->config->get('temp_dir'); |
| | | $body_file = tempnam($temp_dir, 'rcmMsg'); |
| | | $mime_result = $message->saveMessageBody($body_file); |
| | | |
| | | if (is_a($mime_result, 'PEAR_Error')) { |
| | | self::raise_error(array('code' => 650, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Could not create message: ".$mime_result->getMessage()), |
| | | true, false); |
| | | return false; |
| | | } |
| | | |
| | | $msg_body = fopen($body_file, 'r'); |
| | | } |
| | | else { |
| | | */ |
| | | // \r\n is must-have here |
| | | $this->_body = $message->get() . "\r\n"; |
| | | /* |
| | | } |
| | | */ |
| | | } |
| | | |
| | | /** |
| | | * Check if the message is multipart (requires PGP/MIME) |
| | | * |
| | | * @return bool True if it is multipart, otherwise False |
| | | */ |
| | | function isMultipart() |
| | | { |
| | | return $this->_message instanceof enigma_mime_message |
| | | || !empty($this->_message->_parts) || $this->_message->getHTMLBody(); |
| | | } |
| | | |
| | | /** |
| | | * Get e-mail address of message sender |
| | | * |
| | | * @return string Sender address |
| | | */ |
| | | function getFromAddress() |
| | | { |
| | | // get sender address |
| | | $headers = $this->_message->headers(); |
| | | $from = rcube_mime::decode_address_list($headers['From'], 1, false, null, true); |
| | | $from = $from[1]; |
| | | |
| | | return $from; |
| | | } |
| | | |
| | | /** |
| | | * Get recipients' e-mail addresses |
| | | * |
| | | * @return array Recipients' addresses |
| | | */ |
| | | function getRecipients() |
| | | { |
| | | // get sender address |
| | | $headers = $this->_message->headers(); |
| | | $to = rcube_mime::decode_address_list($headers['To'], null, false, null, true); |
| | | $cc = rcube_mime::decode_address_list($headers['Cc'], null, false, null, true); |
| | | $bcc = rcube_mime::decode_address_list($headers['Bcc'], null, false, null, true); |
| | | |
| | | $recipients = array_unique(array_merge($to, $cc, $bcc)); |
| | | $recipients = array_diff($recipients, array('undisclosed-recipients:')); |
| | | |
| | | return $recipients; |
| | | } |
| | | |
| | | /** |
| | | * Get original message body, to be encrypted/signed |
| | | * |
| | | * @return string Message body |
| | | */ |
| | | function getOrigBody() |
| | | { |
| | | $_headers = $this->_message->headers(); |
| | | $headers = array(); |
| | | |
| | | if ($_headers['Content-Transfer-Encoding']) { |
| | | $headers[] = 'Content-Transfer-Encoding: ' . $_headers['Content-Transfer-Encoding']; |
| | | } |
| | | $headers[] = 'Content-Type: ' . $_headers['Content-Type']; |
| | | |
| | | return implode("\r\n", $headers) . "\r\n\r\n" . $this->_body; |
| | | } |
| | | |
| | | /** |
| | | * Register signature attachment |
| | | * |
| | | * @param string Signature body |
| | | */ |
| | | function addPGPSignature($body) |
| | | { |
| | | $this->_signature = $body; |
| | | } |
| | | |
| | | /** |
| | | * Register encrypted body |
| | | * |
| | | * @param string Encrypted body |
| | | */ |
| | | function setPGPEncryptedBody($body) |
| | | { |
| | | $this->_encrypted = $body; |
| | | } |
| | | |
| | | /** |
| | | * Builds the multipart message. |
| | | * |
| | | * @param array $params Build parameters that change the way the email |
| | | * is built. Should be associative. See $_build_params. |
| | | * @param resource $filename Output file where to save the message instead of |
| | | * returning it |
| | | * @param boolean $skip_head True if you want to return/save only the message |
| | | * without headers |
| | | * |
| | | * @return mixed The MIME message content string, null or PEAR error object |
| | | * @access public |
| | | */ |
| | | function get($params = null, $filename = null, $skip_head = false) |
| | | { |
| | | if (isset($params)) { |
| | | while (list($key, $value) = each($params)) { |
| | | $this->_build_params[$key] = $value; |
| | | } |
| | | } |
| | | |
| | | $this->_checkParams(); |
| | | |
| | | if ($this->_type == self::PGP_SIGNED) { |
| | | $body = "This is an OpenPGP/MIME signed message (RFC 4880 and 3156)"; |
| | | $params = array( |
| | | 'content_type' => "multipart/signed; micalg=pgp-sha1; protocol=\"application/pgp-signature\"", |
| | | 'eol' => $this->_build_params['eol'], |
| | | ); |
| | | |
| | | $message = new Mail_mimePart($body, $params); |
| | | |
| | | if (!empty($this->_body)) { |
| | | $headers = $this->_message->headers(); |
| | | $params = array('content_type' => $headers['Content-Type']); |
| | | |
| | | if ($headers['Content-Transfer-Encoding']) { |
| | | $params['encoding'] = $headers['Content-Transfer-Encoding']; |
| | | } |
| | | |
| | | $message->addSubpart($this->_body, $params); |
| | | } |
| | | |
| | | if (!empty($this->_signature)) { |
| | | $message->addSubpart($this->_signature, array( |
| | | 'filename' => 'signature.asc', |
| | | 'content_type' => 'application/pgp-signature', |
| | | 'disposition' => 'attachment', |
| | | 'description' => 'OpenPGP digital signature', |
| | | )); |
| | | } |
| | | } |
| | | else if ($this->_type == self::PGP_ENCRYPTED) { |
| | | $body = "This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)"; |
| | | $params = array( |
| | | 'content_type' => "multipart/encrypted; protocol=\"application/pgp-encrypted\"", |
| | | 'eol' => $this->_build_params['eol'], |
| | | ); |
| | | |
| | | $message = new Mail_mimePart($body, $params); |
| | | |
| | | $message->addSubpart('Version: 1', array( |
| | | 'content_type' => 'application/pgp-encrypted', |
| | | 'description' => 'PGP/MIME version identification', |
| | | )); |
| | | |
| | | $message->addSubpart($this->_encrypted, array( |
| | | 'content_type' => 'application/octet-stream', |
| | | 'description' => 'PGP/MIME encrypted message', |
| | | 'disposition' => 'inline', |
| | | 'filename' => 'encrypted.asc', |
| | | )); |
| | | } |
| | | |
| | | // Use saved boundary |
| | | if (!empty($this->_build_params['boundary'])) { |
| | | $boundary = $this->_build_params['boundary']; |
| | | } |
| | | else { |
| | | $boundary = null; |
| | | } |
| | | |
| | | // Write output to file |
| | | if ($filename) { |
| | | // Append mimePart message headers and body into file |
| | | $headers = $message->encodeToFile($filename, $boundary, $skip_head); |
| | | if ($this->_isError($headers)) { |
| | | return $headers; |
| | | } |
| | | $this->_headers = array_merge($this->_headers, $headers); |
| | | return null; |
| | | } |
| | | else { |
| | | $output = $message->encode($boundary, $skip_head); |
| | | if ($this->_isError($output)) { |
| | | return $output; |
| | | } |
| | | $this->_headers = array_merge($this->_headers, $output['headers']); |
| | | return $output['body']; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get Content-Type and Content-Transfer-Encoding headers of the message |
| | | * |
| | | * @return array Headers array |
| | | * @access private |
| | | */ |
| | | function _contentHeaders() |
| | | { |
| | | $this->_checkParams(); |
| | | |
| | | $eol = !empty($this->_build_params['eol']) ? $this->_build_params['eol'] : "\r\n"; |
| | | |
| | | // multipart message: and boundary |
| | | if (!empty($this->_build_params['boundary'])) { |
| | | $boundary = $this->_build_params['boundary']; |
| | | } |
| | | else if (!empty($this->_headers['Content-Type']) |
| | | && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m) |
| | | ) { |
| | | $boundary = $m[1]; |
| | | } |
| | | else { |
| | | $boundary = '=_' . md5(rand() . microtime()); |
| | | } |
| | | |
| | | $this->_build_params['boundary'] = $boundary; |
| | | |
| | | if ($this->_type == self::PGP_SIGNED) { |
| | | $headers['Content-Type'] = "multipart/signed; micalg=pgp-sha1;$eol" |
| | | ." protocol=\"application/pgp-signature\";$eol" |
| | | ." boundary=\"$boundary\""; |
| | | } |
| | | else if ($this->_type == self::PGP_ENCRYPTED) { |
| | | $headers['Content-Type'] = "multipart/encrypted;$eol" |
| | | ." protocol=\"application/pgp-encrypted\";$eol" |
| | | ." boundary=\"$boundary\""; |
| | | } |
| | | |
| | | return $headers; |
| | | } |
| | | } |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | Signature class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | SubKey class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | public $has_private; |
| | | public $can_sign; |
| | | public $can_encrypt; |
| | | |
| | | |
| | | /** |
| | | * Converts internal ID to short ID |
| | | * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | User Interface for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | * |
| | | * @param string Preferences section |
| | | */ |
| | | function init($section='') |
| | | function init() |
| | | { |
| | | $this->add_js(); |
| | | |
| | |
| | | |
| | | $data = array('keyid' => key($data), 'user' => $data[key($data)]); |
| | | |
| | | $this->rc->output->set_env('enigma_password_request', $data); |
| | | if ($this->rc->action == 'send') { |
| | | $this->rc->output->command('enigma_password_request', $data); |
| | | } |
| | | else { |
| | | $this->rc->output->set_env('enigma_password_request', $data); |
| | | } |
| | | |
| | | // add some labels to client |
| | | $this->rc->output->add_label('enigma.enterkeypasstitle', 'enigma.enterkeypass', |
| | |
| | | $attrib['name'] = $attrib['id']; |
| | | |
| | | $this->rc->output->set_env('contentframe', $attrib['name']); |
| | | $this->rc->output->set_env('blankpage', $attrib['src'] ? |
| | | $this->rc->output->set_env('blankpage', $attrib['src'] ? |
| | | $this->rc->output->abs_url($attrib['src']) : 'program/resources/blank.gif'); |
| | | |
| | | return $this->rc->output->frame($attrib); |
| | |
| | | $page = max(intval(rcube_utils::get_input_value('_p', rcube_utils::INPUT_GPC)), 1); |
| | | $search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC); |
| | | |
| | | // define list of cols to be displayed |
| | | // $a_show_cols = array('name'); |
| | | |
| | | // Get the list |
| | | $list = $this->enigma->engine->list_keys($search); |
| | | |
| | |
| | | $this->rc->output->show_message('enigma.keylisterror', 'error'); |
| | | else if (empty($list)) |
| | | $this->rc->output->show_message('enigma.nokeysfound', 'notice'); |
| | | else { |
| | | if (is_array($list)) { |
| | | // Save the size |
| | | $listsize = count($list); |
| | | else if (is_array($list)) { |
| | | // Save the size |
| | | $listsize = count($list); |
| | | |
| | | // Sort the list by key (user) name |
| | | usort($list, array('enigma_key', 'cmp')); |
| | | // Sort the list by key (user) name |
| | | usort($list, array('enigma_key', 'cmp')); |
| | | |
| | | // Slice current page |
| | | $list = array_slice($list, ($page - 1) * $pagesize, $pagesize); |
| | | // Slice current page |
| | | $list = array_slice($list, ($page - 1) * $pagesize, $pagesize); |
| | | $size = count($list); |
| | | |
| | | $size = count($list); |
| | | |
| | | // Add rows |
| | | foreach ($list as $key) { |
| | | $this->rc->output->command('enigma_add_list_row', |
| | | array('name' => rcube::Q($key->name), 'id' => $key->id)); |
| | | } |
| | | // Add rows |
| | | foreach ($list as $key) { |
| | | $this->rc->output->command('enigma_add_list_row', |
| | | array('name' => rcube::Q($key->name), 'id' => $key->id)); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private function get_rowcount_text($all=0, $curr_count=0, $page=1) |
| | | { |
| | | if (!$curr_count) |
| | | if (!$curr_count) { |
| | | $out = $this->enigma->gettext('nokeysfound'); |
| | | } |
| | | else { |
| | | $pagesize = $this->rc->config->get('pagesize', 100); |
| | | $first = ($page - 1) * $pagesize; |
| | | $first = ($page - 1) * $pagesize; |
| | | |
| | | $out = $this->enigma->gettext(array( |
| | | 'name' => 'keysfromto', |
| | |
| | | |
| | | private function compose_ui() |
| | | { |
| | | /* |
| | | $this->add_css(); |
| | | |
| | | // Options menu button |
| | | // @TODO: make this work with non-default skins |
| | | $this->enigma->add_button(array( |
| | | 'type' => 'link', |
| | | 'command' => 'plugin.enigma', |
| | | 'onclick' => "rcmail.command('menu-open', 'enigmamenu', event.target, event)", |
| | | 'class' => 'button enigma', |
| | | 'title' => 'securityoptions', |
| | | 'label' => 'securityoptions', |
| | | 'title' => 'encryptionoptions', |
| | | 'label' => 'encryption', |
| | | 'domain' => $this->enigma->ID, |
| | | 'width' => 32, |
| | | 'height' => 32 |
| | |
| | | |
| | | // Options menu contents |
| | | $this->enigma->add_hook('render_page', array($this, 'compose_menu')); |
| | | */ |
| | | } |
| | | |
| | | function compose_menu($p) |
| | | { |
| | | $menu = new html_table(array('cols' => 2)); |
| | | $menu = new html_table(array('cols' => 2)); |
| | | $chbox = new html_checkbox(array('value' => 1)); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmadefaultopt'), |
| | | rcube::Q($this->enigma->gettext('identdefault')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_default', 'id' => 'enigmadefaultopt'))); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmasignopt'), |
| | | rcube::Q($this->enigma->gettext('signmsg')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_sign', 'id' => 'enigmasignopt'))); |
| | | $menu->add(null, $chbox->show($this->rc->config->get('enigma_sign_all') ? 1 : 0, |
| | | array('name' => '_enigma_sign', 'id' => 'enigmasignopt'))); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmacryptopt'), |
| | | $menu->add(null, html::label(array('for' => 'enigmaencryptopt'), |
| | | rcube::Q($this->enigma->gettext('encryptmsg')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_crypt', 'id' => 'enigmacryptopt'))); |
| | | $menu->add(null, $chbox->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0, |
| | | array('name' => '_enigma_encrypt', 'id' => 'enigmaencryptopt'))); |
| | | |
| | | $menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), |
| | | $menu->show()); |
| | | |
| | | $p['content'] = preg_replace('/(<form name="form"[^>]+>)/i', '\\1'."\n$menu", $p['content']); |
| | | $p['content'] .= $menu; |
| | | |
| | | return $p; |
| | | } |
| | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handle message_ready hook (encryption/signing) |
| | | */ |
| | | function message_ready($p) |
| | | { |
| | | $savedraft = !empty($_POST['_draft']) && empty($_GET['_saveonly']); |
| | | |
| | | if (!$savedraft && rcube_utils::get_input_value('_enigma_sign', rcube_utils::INPUT_POST)) { |
| | | $this->enigma->load_engine(); |
| | | $status = $this->enigma->engine->sign_message($p['message']); |
| | | $mode = 'sign'; |
| | | } |
| | | |
| | | if ((!$status instanceof enigma_error) && rcube_utils::get_input_value('_enigma_encrypt', rcube_utils::INPUT_POST)) { |
| | | $this->enigma->load_engine(); |
| | | $status = $this->enigma->engine->encrypt_message($p['message'], null, $savedraft); |
| | | $mode = 'encrypt'; |
| | | } |
| | | |
| | | if ($mode && ($status instanceof enigma_error)) { |
| | | $code = $status->getCode(); |
| | | |
| | | if ($code == enigma_error::E_KEYNOTFOUND) { |
| | | $vars = array('email' => $status->getData('missing')); |
| | | $msg = 'enigma.' . $mode . 'nokey'; |
| | | } |
| | | else if ($code == enigma_error::E_BADPASS) { |
| | | $msg = 'enigma.' . $mode . 'badpass'; |
| | | $type = 'warning'; |
| | | |
| | | $this->password_prompt($status); |
| | | } |
| | | else { |
| | | $msg = 'enigma.' . $mode . 'error'; |
| | | } |
| | | |
| | | $this->rc->output->show_message($msg, $type ?: 'error', $vars); |
| | | $this->rc->output->send('iframe'); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | } |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | User ID class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | Copyright (C) 2010-2015 The Roundcube Dev Team | |
| | | | | |
| | | | This program is distributed in the hope that it will be useful, | |
| | | | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| | | | GNU General Public License for more details. | |
| | | | | |
| | | | You should have received a copy of the GNU General Public License along | |
| | | | with this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['enigma'] = 'Enigma'; |
| | | $labels['encryption'] = 'Encryption'; |
| | | $labels['enigmacerts'] = 'S/MIME Certificates'; |
| | | $labels['enigmakeys'] = 'PGP Keys'; |
| | | $labels['keysfromto'] = 'Keys $from to $to of $count'; |
| | |
| | | $labels['keyattfound'] = 'This message contains attached PGP key(s).'; |
| | | $labels['keyattimport'] = 'Import key(s)'; |
| | | |
| | | $labels['signdefault'] = 'Sign all messages by default'; |
| | | $labels['encryptdefault'] = 'Encrypt all messages by default'; |
| | | |
| | | $labels['createkeys'] = 'Create a new key pair'; |
| | | $labels['importkeys'] = 'Import key(s)'; |
| | | $labels['exportkeys'] = 'Export key(s)'; |
| | |
| | | $labels['keysend'] = 'Send public key in a message'; |
| | | $labels['keychpass'] = 'Change password'; |
| | | |
| | | $labels['securityoptions'] = 'Message security options...'; |
| | | $labels['encryptionoptions'] = 'Encryption options...'; |
| | | $labels['identdefault'] = 'Use settings of selected identity'; |
| | | $labels['encryptmsg'] = 'Encrypt this message'; |
| | | $labels['signmsg'] = 'Digitally sign this message'; |
| | |
| | | $messages['decrypterror'] = 'Decryption failed.'; |
| | | $messages['decryptnokey'] = 'Decryption failed. Private key not found. Key ID: $keyid.'; |
| | | $messages['decryptbadpass'] = 'Decryption failed. Bad password.'; |
| | | $messages['signerror'] = 'Signing failed.'; |
| | | $messages['signnokey'] = 'Signing failed. Private key not found.'; |
| | | $messages['signbadpass'] = 'Signing failed. Bad password.'; |
| | | $messages['encrypterror'] = 'Encryption failed.'; |
| | | $messages['encryptnokey'] = 'Encryption failed. Public key not found for $email.'; |
| | | $messages['nokeysfound'] = 'No keys found'; |
| | | $messages['keyopenerror'] = 'Unable to get key information! Internal error.'; |
| | | $messages['keylisterror'] = 'Unable to list keys! Internal error.'; |
| | |
| | | @version 2010-12-23 |
| | | |
| | | */ |
| | | $labels['enigma'] = 'Enigma'; |
| | | $labels['enigmacerts'] = 'Enigma: Сертификаты (S/MIME)'; |
| | | $labels['enigmakeys'] = 'Enigma: Ключи (PGP)'; |
| | | $labels['keysfromto'] = 'Ключи от $from к $to в количестве $count'; |
| | |
| | | /***** E-mail Compose Page *****/ |
| | | |
| | | #messagetoolbar a.button.enigma { |
| | | text-indent: -5000px; |
| | | background: url(enigma_icons.png) center -122px no-repeat; |
| | | } |
| | | |
| | | #enigmamenu { |
| | | color: white; |
| | | padding: 2px 5px; |
| | | } |
| | | |
| | | |
| | | /***** Keys/Certs Management *****/ |
| | | |
| | |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | #sections-table #rcmrowenigma .section { |
| | | background-image: url(enigma_icons.png); |
| | | background-position: 5px -297px; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | #sections-table #rcmrowenigma.selected .section { |
| | | background-image: url(enigma_icons.png); |
| | | background-position: 5px -321px; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | #mainscreen.enigma #settings-sections, |
| | | #mainscreen.enigma #settings-right |
| | | { |