Merge branch 'master' into dev/elastic

pull/6486/head
Aleksander Machniak 6 years ago
commit c8d133a6a0

@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- SMTP GSSAPI support via krb_authentication plugin (#6417)
- Removed referer_check option (#6440) - Removed referer_check option (#6440)
- Update to TinyMCE 4.8.2 - Update to TinyMCE 4.8.2
- Plugin API: Added 'raise_error' hook (#6199) - Plugin API: Added 'raise_error' hook (#6199)
@ -8,9 +9,11 @@ CHANGELOG Roundcube Webmail
- Password: Added 'modoboa' driver (#6361) - Password: Added 'modoboa' driver (#6361)
- Password: Fix bug where password_dovecotpw_with_method setting could be ignored (#6436) - Password: Fix bug where password_dovecotpw_with_method setting could be ignored (#6436)
- Password: Fix bug where new users could skip forced password change (#6434) - Password: Fix bug where new users could skip forced password change (#6434)
- Elastic: Support new-line char as a separator for pasted recipients (#6460)
- Elastic: Improved UX of search dialogs (#6416) - Elastic: Improved UX of search dialogs (#6416)
- Elastic: Fix unwanted thread expanding when selecting a collapsed thread in non-mobile mode (#6445) - Elastic: Fix unwanted thread expanding when selecting a collapsed thread in non-mobile mode (#6445)
- Log errors caused by low pcre.backtrack_limit when sending a mail message (#6433) - Log errors caused by low pcre.backtrack_limit when sending a mail message (#6433)
- Fix bug where autocomplete list could be displayed out of screen (#6469)
- Fix style/navigation on error page depending on authentication state (#6362) - Fix style/navigation on error page depending on authentication state (#6362)
- Fix so invalid smtp_helo_host is never used, fallback to localhost (#6408) - Fix so invalid smtp_helo_host is never used, fallback to localhost (#6408)
- Fix custom logo size in Elastic (#6424) - Fix custom logo size in Elastic (#6424)
@ -19,6 +22,9 @@ CHANGELOG Roundcube Webmail
- Managesieve: Fix bug where show_real_foldernames setting wasn't respected (#6422) - Managesieve: Fix bug where show_real_foldernames setting wasn't respected (#6422)
- New_user_identity: Fix %fu/%u vars substitution in user specific LDAP params (#6419) - New_user_identity: Fix %fu/%u vars substitution in user specific LDAP params (#6419)
- Fix support for "allow-from <uri>" in "x_frame_options" config option (#6449) - Fix support for "allow-from <uri>" in "x_frame_options" config option (#6449)
- Fix bug where valid content between HTML comments could have been skipped in some cases (#6464)
- Fix multiple VCard field search (#6466)
- Fix session issue on long running requests (#6470)
RELEASE 1.4-beta RELEASE 1.4-beta
---------------- ----------------

@ -19,7 +19,7 @@ REQUIREMENTS
- GD, Imagick (optional thumbnails generation, QR-code) - GD, Imagick (optional thumbnails generation, QR-code)
* PEAR and PEAR packages distributed with Roundcube or external: * PEAR and PEAR packages distributed with Roundcube or external:
- Mail_Mime 1.10.0 or newer - Mail_Mime 1.10.0 or newer
- Net_SMTP 1.7.1 or newer - Net_SMTP 1.8.1 or newer
- Net_Socket 1.0.12 or newer - Net_Socket 1.0.12 or newer
- Net_IDNA2 0.1.1 or newer - Net_IDNA2 0.1.1 or newer
- Auth_SASL 1.0.6 or newer - Auth_SASL 1.0.6 or newer

@ -11,11 +11,10 @@
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"pear/pear-core-minimal": "~1.10.1", "pear/pear-core-minimal": "~1.10.1",
"pear/net_socket": "~1.2.1",
"pear/auth_sasl": "~1.1.0", "pear/auth_sasl": "~1.1.0",
"pear/net_idna2": "~0.2.0", "pear/net_idna2": "~0.2.0",
"pear/mail_mime": "~1.10.0", "pear/mail_mime": "~1.10.0",
"pear/net_smtp": "~1.8.0", "pear/net_smtp": "~1.8.1",
"pear/crypt_gpg": "~1.6.3", "pear/crypt_gpg": "~1.6.3",
"pear/net_sieve": "~1.4.3", "pear/net_sieve": "~1.4.3",
"roundcube/plugin-installer": "~0.1.6", "roundcube/plugin-installer": "~0.1.6",

@ -569,7 +569,7 @@ $config['max_group_members'] = 0;
$config['product_name'] = 'Roundcube Webmail'; $config['product_name'] = 'Roundcube Webmail';
// Add this user-agent to message headers when sending // Add this user-agent to message headers when sending
$config['useragent'] = 'Roundcube Webmail/'.RCMAIL_VERSION; $config['useragent'] = 'Roundcube Webmail/'.RCUBE_VERSION;
// try to load host-specific configuration // try to load host-specific configuration
// see https://github.com/roundcube/roundcubemail/wiki/Configuration:-Multi-Domain-Setup // see https://github.com/roundcube/roundcubemail/wiki/Configuration:-Multi-Domain-Setup

@ -3,7 +3,7 @@
"type": "roundcube-plugin", "type": "roundcube-plugin",
"description": "Kerberos Authentication", "description": "Kerberos Authentication",
"license": "GPLv3+", "license": "GPLv3+",
"version": "1.1", "version": "1.2",
"authors": [ "authors": [
{ {
"name": "Jeroen van Meeuwen", "name": "Jeroen van Meeuwen",

@ -9,5 +9,12 @@
// Unlike $config['default_host'] this must be a string! // Unlike $config['default_host'] this must be a string!
$config['krb_authentication_host'] = ''; $config['krb_authentication_host'] = '';
// GSS API security context // GSSAPI security context.
$config['krb_authentication_context'] = 'imap/kolab.example.org@EXAMPLE.ORG'; // Single value or an array with per-protocol values. Example:
//
// $config['krb_authentication_context'] = array(
// 'imap' => 'imap/host.fqdn@REALM.NAME',
// 'smtp' => 'smtp/host.fqdn@REALM.NAME',
// 'sieve' => 'sieve/host.fqdn@REALM.NAME',
// );
$config['krb_authentication_context'] = 'principal@REALM.NAME';

@ -25,6 +25,7 @@ class krb_authentication extends rcube_plugin
$this->add_hook('login_after', array($this, 'login')); $this->add_hook('login_after', array($this, 'login'));
$this->add_hook('storage_connect', array($this, 'storage_connect')); $this->add_hook('storage_connect', array($this, 'storage_connect'));
$this->add_hook('managesieve_connect', array($this, 'managesieve_connect')); $this->add_hook('managesieve_connect', array($this, 'managesieve_connect'));
$this->add_hook('smtp_connect', array($this, 'smtp_connect'));
} }
/** /**
@ -74,19 +75,41 @@ class krb_authentication extends rcube_plugin
return $args; return $args;
} }
/**
* login_after hook handler
*/
function login($args)
{
// Redirect to the previous QUERY_STRING
if ($this->redirect_query) {
header('Location: ./?' . $this->redirect_query);
exit;
}
return $args;
}
/** /**
* Storage_connect hook handler * Storage_connect hook handler
*/ */
function storage_connect($args) function storage_connect($args)
{ {
if (!empty($_SERVER['REMOTE_USER']) && !empty($_SERVER['KRB5CCNAME'])) { if (!empty($_SERVER['REMOTE_USER']) && !empty($_SERVER['KRB5CCNAME'])) {
// Load plugin's config file $args['gssapi_context'] = $this->gssapi_context('imap');
$this->load_config(); $args['gssapi_cn'] = $_SERVER['KRB5CCNAME'];
$args['auth_type'] = 'GSSAPI';
}
$rcmail = rcmail::get_instance(); return $args;
$context = $rcmail->config->get('krb_authentication_context'); }
$args['gssapi_context'] = $context ?: 'imap/kolab.example.org@EXAMPLE.ORG'; /**
* managesieve_connect hook handler
*/
function managesieve_connect($args)
{
if ((!isset($args['auth_type']) || $args['auth_type'] == 'GSSAPI') && !empty($_SERVER['REMOTE_USER']) && !empty($_SERVER['KRB5CCNAME'])) {
$args['gssapi_context'] = $this->gssapi_context('sieve');
$args['gssapi_cn'] = $_SERVER['KRB5CCNAME']; $args['gssapi_cn'] = $_SERVER['KRB5CCNAME'];
$args['auth_type'] = 'GSSAPI'; $args['auth_type'] = 'GSSAPI';
} }
@ -95,36 +118,38 @@ class krb_authentication extends rcube_plugin
} }
/** /**
* login_after hook handler * smtp_connect hook handler
*/ */
function login($args) function smtp_connect($args)
{ {
// Redirect to the previous QUERY_STRING if ((!isset($args['smtp_auth_type']) || $args['smtp_auth_type'] == 'GSSAPI') && !empty($_SERVER['REMOTE_USER']) && !empty($_SERVER['KRB5CCNAME'])) {
if ($this->redirect_query) { $args['gssapi_context'] = $this->gssapi_context('smtp');
header('Location: ./?' . $this->redirect_query); $args['gssapi_cn'] = $_SERVER['KRB5CCNAME'];
exit; $args['smtp_auth_type'] = 'GSSAPI';
} }
return $args; return $args;
} }
/** /**
* managesieve_connect hook handler * Returns configured GSSAPI context string
*/ */
function managesieve_connect($args) private function gssapi_context($protocol)
{ {
if ((!isset($args['auth_type']) || $args['auth_type'] == 'GSSAPI') && !empty($_SERVER['REMOTE_USER']) && !empty($_SERVER['KRB5CCNAME'])) { // Load plugin's config file
// Load plugin's config file $this->load_config();
$this->load_config();
$rcmail = rcmail::get_instance(); $rcmail = rcmail::get_instance();
$context = $rcmail->config->get('krb_authentication_context'); $context = $rcmail->config->get('krb_authentication_context');
$args['gssapi_context'] = $context ?: 'imap/kolab.example.org@EXAMPLE.ORG'; if (is_array($context)) {
$args['gssapi_cn'] = $_SERVER['KRB5CCNAME']; $context = $context[$protocol];
$args['auth_type'] = 'GSSAPI';
} }
return $args; if (empty($context)) {
rcube::raise_error("Empty GSSAPI context ($protocol).", true);
}
return $context;
} }
} }

@ -5941,9 +5941,20 @@ function rcube_webmail()
// reset content // reset content
ul.innerHTML = ''; ul.innerHTML = '';
this.env.contacts = []; this.env.contacts = [];
// move the results pane right under the input box // move the results pane right under the input box
var pos = $(this.ksearch_input).offset(); var pos = $(this.ksearch_input).offset(),
this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'}); w = $(window).width(),
left = w - pos.left > 200 ? pos.left : w - 200,
width = Math.min(400, w - left);
this.ksearch_pane.css({
left: left + 'px',
top: (pos.top + this.ksearch_input.offsetHeight + 1) + 'px',
maxWidth: width + 'px',
minWidth: '200px',
display: 'none'
});
} }
// add each result line to list // add each result line to list

@ -32,7 +32,7 @@ include_path directory of your webserver. Some classes of the framework require
one or multiple of the following [PEAR][pear] libraries: one or multiple of the following [PEAR][pear] libraries:
- Mail_Mime 1.8.1 or newer - Mail_Mime 1.8.1 or newer
- Net_SMTP 1.7.1 or newer - Net_SMTP 1.8.1 or newer
- Net_Socket 1.0.12 or newer - Net_Socket 1.0.12 or newer
- Net_IDNA2 0.1.1 or newer - Net_IDNA2 0.1.1 or newer
- Auth_SASL 1.0.6 or newer - Auth_SASL 1.0.6 or newer

@ -380,7 +380,7 @@ class rcube_contacts extends rcube_addressbook
foreach ((array)$row[$col] as $value) { foreach ((array)$row[$col] as $value) {
if ($this->compare_search_value($colname, $value, $search, $mode)) { if ($this->compare_search_value($colname, $value, $search, $mode)) {
$found[$colname] = true; $found[$colname] = true;
break 2; break;
} }
} }
} }

@ -306,7 +306,7 @@ abstract class rcube_session
$cache = null; $cache = null;
} }
// use internal data for fast requests (up to 0.5 sec.) // use internal data for fast requests (up to 0.5 sec.)
else if ($key == $this->key && (!$this->vars || $ts - $this->start < 0.5)) { else if ($key == $this->key && (!$this->vars || microtime(true) - $this->start < 0.5)) {
$cache = $this->vars; $cache = $this->vars;
} }
else { // else read data again else { // else read data again

@ -108,7 +108,8 @@ class rcube_smtp
// IDNA Support // IDNA Support
$smtp_host = rcube_utils::idn_to_ascii($smtp_host); $smtp_host = rcube_utils::idn_to_ascii($smtp_host);
$this->conn = new Net_SMTP($smtp_host, $smtp_port, $helo_host, false, 0, $CONFIG['smtp_conn_options']); $this->conn = new Net_SMTP($smtp_host, $smtp_port, $helo_host, false, 0, $CONFIG['smtp_conn_options'],
$CONFIG['gssapi_context'], $CONFIG['gssapi_cn']);
if ($rcube->config->get('smtp_debug')) { if ($rcube->config->get('smtp_debug')) {
$this->conn->setDebug(true, array($this, 'debug_handler')); $this->conn->setDebug(true, array($this, 'debug_handler'));
@ -154,7 +155,7 @@ class rcube_smtp
} }
// attempt to authenticate to the SMTP server // attempt to authenticate to the SMTP server
if ($smtp_user && $smtp_pass) { if (($smtp_user && $smtp_pass) || ($smtp_auth_type == 'GSSAPI')) {
// IDNA Support // IDNA Support
if (strpos($smtp_user, '@')) { if (strpos($smtp_user, '@')) {
$smtp_user = rcube_utils::idn_to_ascii($smtp_user); $smtp_user = rcube_utils::idn_to_ascii($smtp_user);

@ -643,6 +643,9 @@ class rcube_washtml
$html = str_replace($badwordchars, $fixedwordchars, $html); $html = str_replace($badwordchars, $fixedwordchars, $html);
// FIXME: HTML comments handling could be better. The code below can break comments (#6464),
// we should probably do not modify content inside comments at all.
// fix (unknown/malformed) HTML tags before "wash" // fix (unknown/malformed) HTML tags before "wash"
$html = preg_replace_callback('/(<(?!\!)[\/]*)([^\s>]+)([^>]*)/', array($this, 'html_tag_callback'), $html); $html = preg_replace_callback('/(<(?!\!)[\/]*)([^\s>]+)([^>]*)/', array($this, 'html_tag_callback'), $html);
@ -665,9 +668,15 @@ class rcube_washtml
*/ */
public static function html_tag_callback($matches) public static function html_tag_callback($matches)
{ {
// It might be an ending of a comment, ignore (#6464)
if (substr($matches[3], -2) == '--') {
$matches[0] = '';
return implode('', $matches);
}
$tagname = $matches[2]; $tagname = $matches[2];
$tagname = preg_replace(array( $tagname = preg_replace(array(
'/:.*$/', // Microsoft's Smart Tags <st1:xxxx> '/:.*$/', // Microsoft's Smart Tags <st1:xxxx>
'/[^a-z0-9_\[\]\!?-]/i', // forbidden characters '/[^a-z0-9_\[\]\!?-]/i', // forbidden characters
), '', $tagname); ), '', $tagname);

@ -59,12 +59,20 @@
#rcmKSearchpane { #rcmKSearchpane {
width: auto; width: auto;
max-width: none;
overflow: hidden;
li { li {
padding-right: .5rem; padding-right: .5rem;
} }
html.layout-small &,
html.layout-phone & {
bottom: auto;
border: 1px solid @color-input-border;
}
html.layout-phone & {
max-width: 100% !important;
}
} }
html.layout-small, html.layout-small,
@ -106,11 +114,6 @@ html.layout-phone {
width: 100%; width: 100%;
} }
#rcmKSearchpane {
bottom: auto;
border: 1px solid @color-input-border;
}
.popover-header { .popover-header {
display: block; display: block;
border-radius: 0; border-radius: 0;

@ -2892,7 +2892,7 @@ function rcube_elastic_ui()
*/ */
function recipient_input(obj) function recipient_input(obj)
{ {
var list, input, ac_props, var list, input, ac_props, update_lock,
input_len_update = function() { input_len_update = function() {
input.css('width', input.val().length * 10 + 15); input.css('width', input.val().length * 10 + 15);
}, },
@ -2932,29 +2932,41 @@ function rcube_elastic_ui()
else else
recipient.insertBefore(input.parent()); recipient.insertBefore(input.parent());
}, },
update_func = function() { update_func = function(text) {
var text = input.val().replace(/[,;\s]+$/, ''), var result;
result = recipient_input_parser(text);
if (update_lock) {
return;
}
update_lock = true;
text = (text || input.val()).replace(/[,;\s]+$/, '');
result = recipient_input_parser(text);
$.each(result.recipients, function() { $.each(result.recipients, function() {
insert_recipient(this.name, this.email); insert_recipient(this.name, this.email);
}); });
input.val(result.text); // setTimeout() here is needed for proper input reset on paste event
apply_func(); // This is also the reason why we need parse_lock
input_len_update(); setTimeout(function() {
input.val(result.text);
apply_func();
input_len_update();
update_lock = false;
}, 1);
if (result.recipients.length) { return result.recipients.length > 0;
return true;
}
}, },
parse_func = function(e) { parse_func = function(e) {
// Note it can be also executed when autocomplete inserts a recipient
update_func();
if (e.type == 'blur') { if (e.type == 'blur') {
list.removeClass('focus'); list.removeClass('focus');
} }
// On paste the text is not yet in the input we have to use clipboard.
// Also because on paste new-line characters are replaced by spaces (#6460)
update_func(e.type == 'paste' ? (e.originalEvent.clipboardData || window.clipboardData).getData('text') : null);
}, },
keydown_func = function(e) { keydown_func = function(e) {
// On Backspace remove the last recipient // On Backspace remove the last recipient
@ -2963,8 +2975,8 @@ function rcube_elastic_ui()
apply_func(); apply_func();
return false; return false;
} }
// Here we add a recipient box when the separator character (,;) was pressed // Here we add a recipient box when the separator (,;) or Enter was pressed
else if (e.key == ',' || e.key == ';') { else if (e.key == ',' || e.key == ';' || e.key == 'Enter') {
if (update_func()) { if (update_func()) {
return false; return false;
} }
@ -2973,7 +2985,7 @@ function rcube_elastic_ui()
input_len_update(); input_len_update();
}; };
// Create the input elemennt and "editable" area // Create the input element and "editable" area
input = $('<input>').attr({type: 'text', tabindex: $(obj).attr('tabindex')}) input = $('<input>').attr({type: 'text', tabindex: $(obj).attr('tabindex')})
.on('paste change blur', parse_func) .on('paste change blur', parse_func)
.on('keydown', keydown_func) .on('keydown', keydown_func)
@ -3021,6 +3033,9 @@ function rcube_elastic_ui()
*/ */
function recipient_input_parser(text) function recipient_input_parser(text)
{ {
// support new-line as a separator, for paste action (#6460)
text = $.trim(text.replace(/[,;\s]*[\r\n]+/g, ','));
var recipients = [], var recipients = [],
address_rx_part = '(\\S+|("[^"]+"))@\\S+', address_rx_part = '(\\S+|("[^"]+"))@\\S+',
recipient_rx1 = new RegExp('(<' + address_rx_part + '>)'), recipient_rx1 = new RegExp('(<' + address_rx_part + '>)'),

@ -2426,6 +2426,8 @@ ul.toolbarmenu li span.copy {
border: 0; border: 0;
cursor: default; cursor: default;
position: relative; position: relative;
overflow: hidden;
text-overflow: ellipsis;
} }
#rcmKSearchpane ul li i.icon { #rcmKSearchpane ul li i.icon {

@ -98,6 +98,11 @@ class Framework_Washtml extends PHPUnit_Framework_TestCase
$washed = $this->cleanupResult($washer->wash($html)); $washed = $this->cleanupResult($washer->wash($html));
$this->assertEquals('<p>para1</p><p>para2</p>', $washed, "HTML comments - bracket inside"); $this->assertEquals('<p>para1</p><p>para2</p>', $washed, "HTML comments - bracket inside");
$html = "<p><!-- span>1</span -->\n<span>2</span>\n<!-- >3</span --><span>4</span></p>";
$washed = $this->cleanupResult($washer->wash($html));
$this->assertEquals("<p>\n<span>2</span>\n<span>4</span></p>", $washed, "HTML comments (#6464)");
} }
/** /**

Loading…
Cancel
Save