WIP of SMIME support:

- Implement smime ecryption in compose
- Implement passphrase dialog
This commit is contained in:
Hadi Nategh 2017-02-15 12:23:27 +01:00
parent e1e9ab8f8e
commit 116151a092
4 changed files with 151 additions and 53 deletions

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay>
<template id="etemplate.password" template="" lang="" group="0" version="16.1">
<vbox width="250px" class="ui-dialog-content">
<label class="et2_fullWidth" id="message"/>
<hbox>
<image src="password" class="dialog_icon"/>
<hbox>
<passwd id="value" width="80%" blur="enter your passphrase"/>
</hbox>
</hbox>
</vbox>
</template>
</overlay>

View File

@ -212,13 +212,21 @@ class mail_compose
'onExecute' => 'javaScript:app.mail.compose_saveDraft2fm',
'hint' => 'Save the drafted message as eml file into VFS'
),
'sign' => array (
'smime_sign' => array (
'caption' => 'Sign',
'icon' => 'smimeSignature',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.compose_setToggle',
'checkbox' => true,
'hint' => 'Sign your message with smime certificate'
),
'smime_encrypt' => array (
'caption' => 'SMIME',
'icon' => 'smimeEncryption',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.compose_setToggle',
'checkbox' => true,
'hint' => 'Encrypt your message with smime certificate'
)
);
foreach (self::$priorities as $key => $priority)
@ -2346,61 +2354,60 @@ class mail_compose
*/
if ($_formData['attachments'] && $_formData['filemode'] != Vfs\Sharing::ATTACH && !$_autosaving)
{
$attachment_links = $this->getAttachmentLinks($_formData['attachments'], $_formData['filemode'],
$attachment_links = $this->_getAttachmentLinks($_formData['attachments'], $_formData['filemode'],
$_formData['mimeType'] == 'html',
array_unique(array_merge((array)$_formData['to'], (array)$_formData['cc'], (array)$_formData['bcc'])),
$_formData['expiration'], $_formData['password']);
}
if($_formData['mimeType'] == 'html')
switch ($_formData['mimeType'])
{
$body = $_formData['body'];
if ($attachment_links)
{
if (strpos($body, '<!-- HTMLSIGBEGIN -->') !== false)
case 'html':
$body = $_formData['body'];
if ($attachment_links)
{
$body = str_replace('<!-- HTMLSIGBEGIN -->', $attachment_links.'<!-- HTMLSIGBEGIN -->', $body);
if (strpos($body, '<!-- HTMLSIGBEGIN -->') !== false)
{
$body = str_replace('<!-- HTMLSIGBEGIN -->', $attachment_links.'<!-- HTMLSIGBEGIN -->', $body);
}
else
{
$body .= $attachment_links;
}
}
if(!empty($signature))
{
$_mailObject->setBody($this->convertHTMLToText($body, true, true).
($disableRuler ? "\r\n" : "\r\n-- \r\n").
$this->convertHTMLToText($signature, true, true));
$body .= ($disableRuler ?'<br>':'<hr style="border:1px dotted silver; width:90%;">').$signature;
}
else
{
$body .= $attachment_links;
$_mailObject->setBody($this->convertHTMLToText($body, true, true));
}
}
if(!empty($signature))
{
$_mailObject->setBody($this->convertHTMLToText($body, true, true).
($disableRuler ? "\r\n" : "\r\n-- \r\n").
$this->convertHTMLToText($signature, true, true));
// convert URL Images to inline images - if possible
if (!$_autosaving) $inline_images = Mail::processURL2InlineImages($_mailObject, $body, $mail_bo);
if (strpos($body,"<!-- HTMLSIGBEGIN -->")!==false)
{
$body = str_replace(array('<!-- HTMLSIGBEGIN -->','<!-- HTMLSIGEND -->'),'',$body);
}
$_mailObject->setHtmlBody($body, null, false); // false = no automatic alternative, we called setBody()
break;
case 'openpgp':
$_mailObject->setOpenPgpBody($_formData['body']);
break;
default:
$body = $this->convertHTMLToText($_formData['body'],false);
$body .= ($disableRuler ?'<br>':'<hr style="border:1px dotted silver; width:90%;">').$signature;
}
else
{
$_mailObject->setBody($this->convertHTMLToText($body, true, true));
}
// convert URL Images to inline images - if possible
if (!$_autosaving) $inline_images = Mail::processURL2InlineImages($_mailObject, $body, $mail_bo);
if (strpos($body,"<!-- HTMLSIGBEGIN -->")!==false)
{
$body = str_replace(array('<!-- HTMLSIGBEGIN -->','<!-- HTMLSIGEND -->'),'',$body);
}
$_mailObject->setHtmlBody($body, null, false); // false = no automatic alternative, we called setBody()
}
elseif ($_formData['mimeType'] == 'openpgp')
{
$_mailObject->setOpenPgpBody($_formData['body']);
}
else
{
$body = $this->convertHTMLToText($_formData['body'],false);
if ($attachment_links) $body .= $attachment_links;
if ($attachment_links) $body .= $attachment_links;
#$_mailObject->Body = $_formData['body'];
if(!empty($signature)) {
$body .= ($disableRuler ?"\r\n":"\r\n-- \r\n").
$this->convertHTMLToText($signature,true,true);
}
$_mailObject->setBody($body);
#$_mailObject->Body = $_formData['body'];
if(!empty($signature)) {
$body .= ($disableRuler ?"\r\n":"\r\n-- \r\n").
$this->convertHTMLToText($signature,true,true);
}
$_mailObject->setBody($body);
}
//error_log(__METHOD__.__LINE__.array2string($_formData['attachments']));
// add the attachments
@ -2499,7 +2506,7 @@ class mail_compose
* @param string $password =null
* @return string might be empty if no file attachments found
*/
protected function getAttachmentLinks(array $attachments, $filemode, $html, $recipients=array(), $expiration=null, $password=null)
protected function _getAttachmentLinks(array $attachments, $filemode, $html, $recipients=array(), $expiration=null, $password=null)
{
if ($filemode == Vfs\Sharing::ATTACH) return '';
@ -2783,6 +2790,8 @@ class mail_compose
$this->sessionData['to_infolog'] = $_formData['to_infolog'];
$this->sessionData['to_tracker'] = $_formData['to_tracker'];
$this->sessionData['attachments'] = $_formData['attachments'];
$this->sessionData['smime_sign'] = $_formData['smime_sign'];
$this->sessionData['smime_encrypt'] = $_formData['smime_encrypt'];
if (isset($_formData['lastDrafted']) && !empty($_formData['lastDrafted']))
{
@ -2966,6 +2975,43 @@ class mail_compose
#error_log($this->errorInfo);
return false;
}
// SMIME SIGN/ENCRYPTION
if ($_formData['smime_sign'] == 'on' || $_formData['smime_encrypt'] == 'on' )
{
try {
if ($_formData['smime_sign'] == 'on')
{
$smime_part = $this->_encrypt(
'',//TODO
$_formData['smime_encrypt'] == 'on'? Mail\Smime::TYPE_SIGN_ENCRYPT: Mail\Smime::TYPE_SIGN,
$_formData['to'],
$identity['ident_email'],
$_formData['smime_passphrase']
);
if ($smime_part['smime_pass_require'])
{
$response = Api\Json\Response::get();
$response->call('app.mail.smimePassDialog');
return false;
}
}
elseif ($_formData['smime_sign'] == 'off' && $_formData['smime_encrypt'] == 'on')
{
$smime_part = $this->_encrypt(
'',//TODO
Mail\Smime::TYPE_ENCRYPT,
$_formData['to'],
$identity['ident_email']
);
}
//TODO Set signed or encrypted mime part
}
catch (Exception $ex)
{
throw new Api\Exception\WrongUserinput($ex->getMessage());
}
}
// set a higher timeout for big messages
@set_time_limit(120);
@ -3581,30 +3627,35 @@ class mail_compose
* @return Horde_Mime_Part returns encrypted message
* @throws Api\Exception\WrongUserinput if no certificate found
*/
function _encrypt(Horde_Mime_part $message, $type, $recipients, $sender)
protected function _encrypt(Horde_Mime_part $message, $type, $recipients, $sender, $passphrase='')
{
$AB = new addressbook_bo();
$smime = new Mail\Smime();
if (isset($sender) && ($type == Mail\Smime::TYPE_SIGN || $type == Mail\Smime::TYPE_SIGN_ENCRYPT))
{
$sender_cert = $AB->get_smime_keys($sender);
$smime = new Mail\Smime();
if ($sender_cert)
{
$senderPubKey = $smime->get_publickey($sender_cert[$sender]);
$senderPubKey = $sender_cert[$sender];
}
else
{
throw new Api\Exception\WrongUserinput('no certificate found to sign the messase');
}
$credents = Mail\Credentials::read($this->mail_bo->profileID, Mail\Credentials::SMIME, $GLOBALS['egw_info']['user']['account_id']);
$privkey = $credents['acc_smime_password'];
if (!$smime->verifyPassphrase($privkey, $passphrase))
{
return array('smime_pass_require' => true);
}
}
if (isset($recipients) && ($type == Mail\Smime::TYPE_ENCRYPT || $type == Mail\Smime::TYPE_SIGN_ENCRYPT))
{
$recipients_certs = $AB->get_smime_keys($recipients);
$recipientsPubKeys = array_Map(array ($smime, 'get_publickey'), $recipients_certs);
if (!$recipients_certs) throw new Api\Exception\WrongUserinput('no certificate found from the recipients to sign/encrypt the messase');
}
@ -3612,15 +3663,15 @@ class mail_compose
$sign_params = array(
'type' => 'signature',
'pubkey' => $senderPubKey,
'prikey' => '',
'passphrase'=> '',
'privkey' => $privkey,
'passphrase'=> $passphrase,
'sigtype' => 'detach',
'certs' => ''
);
// parameters to pass on for encrypt mime part
$encrypt_params = array(
'type' => 'message',
'pubkey' => $recipientsPubKeys
'pubkey' => $recipients_certs
);
switch ($type)
{

View File

@ -5528,5 +5528,33 @@ app.classes.mail = AppJS.extend(
url = this.et2.getArrayMgr("content").getEntry('smimeSigUrl');
}
window.egw.openPopup(url,'700','400');
},
/**
* smime password dialog
*/
smimePassDialog: function ()
{
var self = this;
et2_createWidget("dialog",
{
callback: function(_button_id, _value)
{
if (_button_id && _value)
{
var pass = self.et2.getWidgetById('smime_passphrase');
pass.set_value(_value.value);
}
},
title: egw.lang('Request for passphrase'),
buttons: et2_dialog.BUTTONS_OK_CANCEL,
value:{
content:{
value: '',
message: self.egw.lang('Looks like your certificate is password protected. Please enter your passphrase and try to send again.')
}},
template: egw.webserverUrl+'/api/templates/default/password.xet',
resizable: false
}, et2_dialog._create_parent('mail'));
}
});

View File

@ -12,6 +12,9 @@
<checkbox statustext="check to save as trackerentry on send" id="to_tracker" options="on,off"/>
<checkbox statustext="check to save as calendar event on send" id="to_calendar" options="on,off"/>
<checkbox statustext="check to recieve a notification when the message is read (note: not all clients support this and/or the reciever may not authorize the notification)" id="disposition" options="on,off"/>
<checkbox statustext="check to sign the message on send" id="smime_sign" options="on,off"/>
<checkbox statustext="check to encrypt the message on send" id="smime_encrypt" options="on,off"/>
<passwd id="smime_passphrase"/>
<taglist id="to_integrate_ids"/>
<menulist>
<menupopup id="priority"/>