Merge branch 'dev/gnupg21'

pull/5498/head
Aleksander Machniak 8 years ago
commit 2ae1da4b1d

@ -24,6 +24,10 @@ $config['enigma_pgp_binary'] = '';
// It's used with GnuPG 2.x.
$config['enigma_pgp_agent'] = '';
// Location of gpgconf binary. By default it will be auto-detected.
// It's used with GnuPG >= 2.1.
$config['enigma_pgp_gpgconf'] = '';
// Enables signatures verification feature.
$config['enigma_signatures'] = true;

@ -99,7 +99,7 @@ rcube_webmail.prototype.enigma_key_create_save = function()
size = $('#key-size').val();
$('[name="identity[]"]:checked').each(function() {
users.push(this.value);
users.push(this.value);
});
// validate the form
@ -124,7 +124,8 @@ rcube_webmail.prototype.enigma_key_create_save = function()
openpgp.generateKeyPair(options).then(function(keypair) {
// success
var post = {_a: 'import', _keys: keypair.privateKeyArmored, _generated: 1};
var post = {_a: 'import', _keys: keypair.privateKeyArmored, _generated: 1,
_passwd: password, _keyid: keypair.key.primaryKey.fingerprint};
// send request to server
rcmail.http_post('plugin.enigmakeys', post, lock);
@ -166,12 +167,12 @@ rcube_webmail.prototype.enigma_export = function(selected)
var priv = false,
list = this.keys_list,
keys = selected ? list.get_selection().join(',') : '*',
args = {_a: 'export', _keys: keys};
args = {_keys: keys};
if (!keys.length)
return;
// find out wether selected keys are private
// find out whether selected keys are private
if (keys == '*')
priv = true;
else
@ -191,7 +192,7 @@ rcube_webmail.prototype.enigma_export = function(selected)
[{
text: this.get_label('enigma.onlypubkeys'),
click: function(e) {
rcmail.goto_url('plugin.enigmakeys', args, false, true);
rcmail.enigma_export_submit(args);
$(this).remove();
}
},
@ -199,20 +200,40 @@ rcube_webmail.prototype.enigma_export = function(selected)
text: this.get_label('enigma.withprivkeys'),
click: function(e) {
args._priv = 1;
rcmail.goto_url('plugin.enigmakeys', args, false, true);
rcmail.enigma_export_submit(args);
$(this).remove();
}
}],
{width: 400}
);
this.goto_url('plugin.enigmakeys', args, false, true);
this.enigma_export_submit(args);
};
// Sumbitting request for key(s) export
// Done this way to handle password input
rcube_webmail.prototype.enigma_export_submit = function(data)
{
var id = 'keyexport-' + new Date().getTime(),
form = $('<form>').attr({target: id, method: 'post', style: 'display:none',
action: '?_action=plugin.enigmakeys&_task=settings&_a=export'}),
iframe = $('<iframe>').attr({name: id, style: 'display:none'})
form.append($('<input>').attr({name: '_token', value: this.env.request_token}));
$.each(data, function(i, v) {
form.append($('<input>').attr({name: i, value: v}));
});
iframe.appendTo(document.body);
form.appendTo(document.body).submit();
};
// Submit key(s) import form
rcube_webmail.prototype.enigma_import = function()
{
var form, file;
var form, file, lock,
id = 'keyexport-' + new Date().getTime(),
iframe = $('<iframe>').attr({name: id, style: 'display:none'});
if (form = this.gui_objects.importform) {
file = document.getElementById('rcmimportfile');
@ -221,13 +242,11 @@ rcube_webmail.prototype.enigma_import = function()
return;
}
var lock = this.set_busy(true, 'importwait');
form.action = this.add_url(form.action, '_unlock', lock);
form.submit();
this.lock_form(form, true);
}
lock = this.set_busy(true, 'importwait');
iframe.appendTo(document.body);
$(form).attr({target: id, action: this.add_url(form.action, '_unlock', lock)})
.submit();
}
};
// Ssearch for key(s) for import
@ -516,12 +535,23 @@ rcube_webmail.prototype.enigma_password_request = function(data)
// submit entered password
rcube_webmail.prototype.enigma_password_submit = function(data)
{
var lock, form;
if (this.env.action == 'compose' && !data['compose-init']) {
return this.enigma_password_compose_submit(data);
}
else if (this.env.action == 'plugin.enigmakeys' && (form = this.gui_objects.importform)) {
if (!$('input[name="_keyid"]', form).length) {
$(form).append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key}))
.append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password}))
}
var lock = this.set_busy(true, 'loading'),
form = $('<form>').attr({method: 'post', action: data.action || location.href, style: 'display:none'})
return this.enigma_import();
}
lock = data.nolock ? null : this.set_busy(true, 'loading');
form = $('<form>')
.attr({method: 'post', action: data.action || location.href, style: 'display:none'})
.append($('<input>').attr({type: 'hidden', name: '_keyid', value: data.key}))
.append($('<input>').attr({type: 'hidden', name: '_passwd', value: data.password}))
.append($('<input>').attr({type: 'hidden', name: '_token', value: this.env.request_token}))
@ -529,14 +559,14 @@ rcube_webmail.prototype.enigma_password_submit = function(data)
// Additional form fields for request parameters
$.each(data, function(i, v) {
if (i.indexOf('input') == 0)
form.append($('<input>').attr({type: 'hidden', name: i.substring(5), value: v}))
if (i.indexOf('input') == 0)
form.append($('<input>').attr({type: 'hidden', name: i.substring(5), value: v}))
});
if (data.iframe) {
var name = 'enigma_frame_' + (new Date()).getTime(),
frame = $('<iframe>').attr({style: 'display:none', name: name}).appendTo(document.body);
form.attr('target', name);
var name = 'enigma_frame_' + (new Date()).getTime(),
frame = $('<iframe>').attr({style: 'display:none', name: name}).appendTo(document.body);
form.attr('target', name);
}
form.appendTo(document.body).submit();

@ -85,6 +85,8 @@ class enigma extends rcube_plugin
if (empty($_REQUEST['_framed']) || strpos($this->rc->action, 'plugin.enigma') === 0) {
$this->ui->add_css();
}
$this->password_handler();
}
else if ($this->rc->task == 'cli') {
$this->add_hook('user_delete_commit', array($this, 'user_delete'));

@ -77,22 +77,24 @@ abstract class enigma_driver
/**
* Key/Cert file import.
*
* @param string File name or file content
* @param bollean True if first argument is a filename
* @param string File name or file content
* @param bolean True if first argument is a filename
* @param array Optional key => password map
*
* @return mixed Import status array or enigma_error
*/
abstract function import($content, $isfile = false);
abstract function import($content, $isfile = false, $passwords = array());
/**
* Key/Cert export.
*
* @param string Key ID
* @param bool Include private key
* @param array Optional key => password map
*
* @return mixed Key content or enigma_error
*/
abstract function export($key, $with_private = false);
abstract function export($key, $with_private = false, $passwords = array());
/**
* Keys listing.

@ -43,6 +43,7 @@ class enigma_driver_gnupg extends enigma_driver
$debug = $this->rc->config->get('enigma_debug');
$binary = $this->rc->config->get('enigma_pgp_binary');
$agent = $this->rc->config->get('enigma_pgp_agent');
$gpgconf = $this->rc->config->get('enigma_pgp_gpgconf');
if (!$homedir) {
return new enigma_error(enigma_error::INTERNAL,
@ -88,6 +89,9 @@ class enigma_driver_gnupg extends enigma_driver
if ($agent) {
$options['agent'] = $agent;
}
if ($gpgconf) {
$options['gpgconf'] = $gpgconf;
}
// Create Crypt_GPG object
try {
@ -197,14 +201,20 @@ class enigma_driver_gnupg extends enigma_driver
/**
* Key file import.
*
* @param string File name or file content
* @param bollean True if first argument is a filename
* @param string File name or file content
* @param bolean True if first argument is a filename
* @param array Optional key => password map
*
* @return mixed Import status array or enigma_error
*/
public function import($content, $isfile=false)
public function import($content, $isfile = false, $passwords = array())
{
try {
// GnuPG 2.1 requires secret key passphrases on import
foreach ($passwords as $keyid => $pass) {
$this->gpg->addPassphrase($keyid, $pass);
}
if ($isfile)
return $this->gpg->importKeyFile($content);
else
@ -220,15 +230,21 @@ class enigma_driver_gnupg extends enigma_driver
*
* @param string Key ID
* @param bool Include private key
* @param array Optional key => password map
*
* @return mixed Key content or enigma_error
*/
public function export($keyid, $with_private = false)
public function export($keyid, $with_private = false, $passwords = array())
{
try {
$key = $this->gpg->exportPublicKey($keyid, true);
if ($with_private) {
// GnuPG 2.1 requires secret key passphrases on export
foreach ($passwords as $keyid => $pass) {
$this->gpg->addPassphrase($keyid, $pass);
}
$priv = $this->gpg->exportPrivateKey($keyid, true);
$key .= $priv;
}
@ -247,7 +263,7 @@ class enigma_driver_gnupg extends enigma_driver
*
* @return mixed Array of enigma_key objects or enigma_error
*/
public function list_keys($pattern='')
public function list_keys($pattern = '')
{
try {
$keys = $this->gpg->getKeys($pattern);

@ -122,11 +122,11 @@ class enigma_driver_phpssl extends enigma_driver
return $sig;
}
public function import($content, $isfile=false)
public function import($content, $isfile = false, $passwords = array())
{
}
public function export($key, $with_private = false)
public function export($key, $with_private = false, $passwords = array())
{
}

@ -1113,10 +1113,10 @@ class enigma_engine
*
* @return mixed Import status data array or enigma_error
*/
function import_key($content, $isfile=false)
function import_key($content, $isfile = false)
{
$this->load_pgp_driver();
$result = $this->pgp_driver->import($content, $isfile);
$result = $this->pgp_driver->import($content, $isfile, $this->get_passwords());
if ($result instanceof enigma_error) {
rcube::raise_error(array(
@ -1145,7 +1145,7 @@ class enigma_engine
function export_key($key, $fp = null, $include_private = false)
{
$this->load_pgp_driver();
$result = $this->pgp_driver->export($key, $include_private);
$result = $this->pgp_driver->export($key, $include_private, $this->get_passwords());
if ($result instanceof enigma_error) {
rcube::raise_error(array(
@ -1174,7 +1174,7 @@ class enigma_engine
$passwd = rcube_utils::get_input_value('_passwd', rcube_utils::INPUT_POST, true);
if ($keyid && $passwd !== null && strlen($passwd)) {
$this->save_password($keyid, $passwd);
$this->save_password(strtoupper($keyid), $passwd);
}
}

@ -161,7 +161,10 @@ class enigma_ui
$data = array_merge($params, $data);
}
if ($this->rc->action == 'send' || $this->rc->action == 'plugin.enigmaimport') {
// @TODO: Get user name/address when keyid == user,
// it may happen on GnuPG 2.1
if (preg_match('/^(send|plugin.enigmaimport|plugin.enigmakeys)$/', $this->rc->action)) {
$this->rc->output->command('enigma_password_request', $data);
}
else {
@ -464,28 +467,50 @@ class enigma_ui
*/
private function key_export()
{
$this->rc->request_security_check(rcube_utils::INPUT_GET);
$keys = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_GPC);
$priv = rcube_utils::get_input_value('_priv', rcube_utils::INPUT_GPC);
$keys = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_POST);
$priv = rcube_utils::get_input_value('_priv', rcube_utils::INPUT_POST);
$engine = $this->enigma->load_engine();
$list = $keys == '*' ? $engine->list_keys() : explode(',', $keys);
if (is_array($list)) {
if (is_array($list) && ($fp = fopen('php://memory', 'rw'))) {
$filename = 'export.pgp';
if (count($list) == 1) {
$filename = (is_object($list[0]) ? $list[0]->id : $list[0]) . '.pgp';
}
$status = null;
foreach ($list as $key) {
$status = $engine->export_key(is_object($key) ? $key->id : $key, $fp, (bool) $priv);
if ($status instanceof enigma_error) {
$code = $status->getCode();
if ($code == enigma_error::BADPASS) {
$this->password_prompt($status, array(
'input_keys' => $keys,
'input_priv' => 1,
'input_task' => 'settings',
'input_action' => 'plugin.enigmakeys',
'input_a' => 'export',
'action' => '?',
'iframe' => true,
'nolock' => true,
));
fclose($fp);
$this->rc->output->send('iframe');
}
}
}
// send downlaod headers
header('Content-Type: application/pgp-keys');
header('Content-Disposition: attachment; filename="' . $filename . '"');
if ($fp = fopen('php://output', 'w')) {
foreach ($list as $key) {
$engine->export_key(is_object($key) ? $key->id : $key, $fp, (bool) $priv);
}
rewind($fp);
while (!feof($fp)) {
echo fread($fp, 1024 * 1024);
}
fclose($fp);
}
exit;
@ -498,8 +523,9 @@ class enigma_ui
{
// Import process
if ($data = rcube_utils::get_input_value('_keys', rcube_utils::INPUT_POST)) {
// Import from generation form (ajax request)
$this->enigma->load_engine();
$this->enigma->engine->password_handler();
$result = $this->enigma->engine->import_key($data);
if (is_array($result)) {
@ -537,12 +563,15 @@ class enigma_ui
$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation',
array('new' => $result['imported'], 'old' => $result['unchanged']));
$this->rc->output->send('iframe');
}
else if ($result instanceof enigma_error && $result->getCode() == enigma_error::BADPASS) {
$this->password_prompt($result);
}
else {
$this->rc->output->show_message('enigma.keysimportfailed', 'error');
}
$this->rc->output->send('iframe');
}
else if ($err = $_FILES['_file']['error']) {
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
@ -551,6 +580,8 @@ class enigma_ui
} else {
$this->rc->output->show_message('fileuploaderror', 'error');
}
$this->rc->output->send('iframe');
}
$this->rc->output->add_handlers(array(
@ -1074,7 +1105,7 @@ class enigma_ui
));
}
else {
$this->rc->output->show_message($msg, $type ?: 'error', $vars);
$this->rc->output->show_message($msg, 'error', $vars);
}
}

Loading…
Cancel
Save