From 4cc20eef72a4f6e812d9e2203780ed3deb7da986 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 10 Nov 2019 08:56:11 +0100 Subject: [PATCH] Fix bug where cache keys could exceed length limit specified in db schema (#7004) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_cache.php | 29 +++++++++++++++++++++++++- program/lib/Roundcube/rcube_imap.php | 30 +++++++-------------------- program/lib/Roundcube/rcube_ldap.php | 2 +- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4076d0b3c..961990e41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ CHANGELOG Roundcube Webmail - Managesieve: Fix locked UI after opening filter frame (#7007) - Fix PHP warning: "array_merge(): Expected parameter 2 to be an array, null given in sendmail.inc (#7003) +- Fix bug where cache keys could exceed length limit specified in db schema (#7004) RELEASE 1.4.0 ------------- diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php index e266c93bc..f0fd7a35a 100644 --- a/program/lib/Roundcube/rcube_cache.php +++ b/program/lib/Roundcube/rcube_cache.php @@ -156,7 +156,7 @@ class rcube_cache * @param boolean $prefix_mode Enable it to clear all keys starting * with prefix specified in $key */ - public function remove($key=null, $prefix_mode=false) + public function remove($key = null, $prefix_mode = false) { // Remove all keys if ($key === null) { @@ -232,6 +232,33 @@ class rcube_cache $this->cache_changes = array(); } + /** + * A helper to build cache key for specified parameters. + * + * @param string $prefix Key prefix (Max. length 64 characters) + * @param array $params Additional parameters + * + * @return string Key name + */ + public static function key_name($prefix, $params = array()) + { + $cache_key = $prefix; + + if (!empty($params)) { + $func = function($v) { + if (is_array($v)) { + sort($v); + } + return is_string($v) ? $v : serialize($v); + }; + + $params = array_map($func, $params); + $cache_key .= '.' . md5(implode(':', $params)); + } + + return $cache_key; + } + /** * Reads cache entry. * diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index eafb94394..77baf95b6 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -2859,14 +2859,9 @@ class rcube_imap extends rcube_storage * * @return array List of folders */ - public function list_folders_subscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) + public function list_folders_subscribed($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false) { - $cache_key = $root.':'.$name; - if (!empty($filter)) { - $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); - } - $cache_key .= ':'.$rights; - $cache_key = 'mailboxes.'.md5($cache_key); + $cache_key = rcube_cache::key_name('mailboxes', array($root, $name, $filter, $rights)); // get cached folder list $a_mboxes = $this->get_cache($cache_key); @@ -2996,14 +2991,9 @@ class rcube_imap extends rcube_storage * * @return array Indexed array with folder names */ - public function list_folders($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) + public function list_folders($root = '', $name = '*', $filter = null, $rights = null, $skip_sort = false) { - $cache_key = $root.':'.$name; - if (!empty($filter)) { - $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); - } - $cache_key .= ':'.$rights; - $cache_key = 'mailboxes.list.'.md5($cache_key); + $cache_key = rcube_cache::key_name('mailboxes.list', array($root, $name, $filter, $rights)); // get cached folder list $a_mboxes = $this->get_cache($cache_key); @@ -3716,7 +3706,7 @@ class rcube_imap extends rcube_storage } // get cached metadata - $cache_key = 'mailboxes.folder-info.' . $folder; + $cache_key = rcube_cache::key_name('mailboxes.folder-info', array($folder)); $cached = $this->get_cache($cache_key); if (is_array($cached)) { @@ -3886,7 +3876,7 @@ class rcube_imap extends rcube_storage return false; } - $this->clear_cache('mailboxes.folder-info.' . $folder); + $this->clear_cache(rcube_cache::key_name('mailboxes.folder-info', array($folder))); return $this->conn->setACL($folder, $user, $acl); } @@ -4063,13 +4053,7 @@ class rcube_imap extends rcube_storage $entries = (array) $entries; if (!$force) { - // create cache key - // @TODO: this is the simplest solution, but we do the same with folders list - // maybe we should store data per-entry and merge on request - sort($options); - sort($entries); - $cache_key = 'mailboxes.metadata.' . $folder; - $cache_key .= '.' . md5(serialize($options).serialize($entries)); + $cache_key = rcube_cache::key_name('mailboxes.metadata', array($folder, $options, $entries)); // get cached data $cached_data = $this->get_cache($cache_key); diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 1c653d680..8ee6f93bb 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -339,7 +339,7 @@ class rcube_ldap extends rcube_addressbook $search_base_dn = strtr($conf['search_base_dn'], $replaces); $search_filter = strtr($conf['search_filter'], $replaces); - $cache_key = 'DN.' . md5("$host:$search_bind_dn:$search_base_dn:$search_filter:" . $conf['search_bind_pw']); + $cache_key = rcube_cache::key_name('DN', array($host, $search_bind_dn, $search_base_dn, $search_filter, $conf['search_bind_pw'])); if ($this->cache && ($dn = $this->cache->get($cache_key))) { $replaces['%dn'] = $dn;