From 3d57827d8c6229c250525286947f5db8d3fe3e26 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 19 Sep 2017 15:30:13 +0200 Subject: [PATCH] fix lost picture when pubkeys get updated/added via mail account dialog and vCard, CardDAV or eSync export --- addressbook/inc/class.addressbook_bo.inc.php | 53 ++++++++++++------- .../inc/class.addressbook_vcal.inc.php | 32 ++++++++++- .../inc/class.addressbook_zpush.inc.php | 4 ++ 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index 35d8d70870..91418d2e4a 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -251,6 +251,7 @@ class addressbook_bo extends Api\Contacts { $contact['pubkey'] = preg_replace($key_regexp, $key, $contact['pubkey']); } + $contact['photo_unchanged'] = true; // otherwise photo will be lost, because $contact['jpegphoto'] is not set if ($this->check_perms(Acl::EDIT, $contact) && $this->save($contact)) { if ($path) @@ -283,7 +284,7 @@ class addressbook_bo extends Api\Contacts * * EMail addresses are lowercased to make search case-insensitive * - * @param string|int|array $recipients (array of) email addresses or numeric account-ids + * @param string|int|array $recipients (array of) email addresses or numeric account-ids or "contact:$id" for contacts by id * @param boolean $pgp true: PGP, false: S/Mime public keys * @return array email|account_id => key pairs */ @@ -293,18 +294,6 @@ class addressbook_bo extends Api\Contacts if (!is_array($recipients)) $recipients = array($recipients); - if ($pgp) - { - $key_regexp = self::$pgp_key_regexp; - $criteria_filter = '%-----BEGIN PGP PUBLIC KEY BLOCK-----%'; - $file = Api\Contacts::FILES_PGP_PUBKEY; - } - else - { - $key_regexp = Api\Mail\Smime::$certificate_regexp; - $criteria_filter = '%-----BEGIN CERTIFICATE-----%'; - $file = Api\Contacts::FILES_SMIME_PUBKEY; - } $criteria = $result = array(); foreach($recipients as &$recipient) { @@ -320,26 +309,52 @@ class addressbook_bo extends Api\Contacts foreach($this->search($criteria, array('account_id', 'contact_email', 'contact_pubkey', 'contact_id'), '', '', '', false, 'OR', false, null) as $contact) { - $matches = null; // first check for file and second for pubkey field (LDAP, AD or old SQL) - if (($content = @file_get_contents(Api\Link::vfs_path('addressbook', $contact['id'], $file))) && - preg_match($key_regexp, $content, $matches) || - preg_match($key_regexp, $contact['pubkey'], $matches)) + if (($content = $this->get_key($contact, $pgp))) { $contact['email'] = strtolower($contact['email']); if (empty($criteria['account_id']) || in_array($contact['email'], $recipients)) { - $result[$contact['email']] = $matches[0]; + $result[$contact['email']] = $content; } else { - $result[$contact['account_id']] = $matches[0]; + $result[$contact['account_id']] = $content; } } } return $result; } + /** + * Extract PGP or S/Mime pubkey from contact array + * + * @param array $contact + * @param boolean $pgp + * @return string pubkey or NULL + */ + function get_key(array $contact, $pgp) + { + if ($pgp) + { + $key_regexp = self::$pgp_key_regexp; + $file = Api\Contacts::FILES_PGP_PUBKEY; + } + else + { + $key_regexp = Api\Mail\Smime::$certificate_regexp; + $file = Api\Contacts::FILES_SMIME_PUBKEY; + } + $matches = null; + if (($content = @file_get_contents(Api\Link::vfs_path('addressbook', $contact['id'], $file))) && + preg_match($key_regexp, $content, $matches) || + preg_match($key_regexp, $contact['pubkey'], $matches)) + { + return $matches[0]; + } + return null; + } + /** * Search addressbook for SMIME Certificate keys of given recipients * diff --git a/addressbook/inc/class.addressbook_vcal.inc.php b/addressbook/inc/class.addressbook_vcal.inc.php index f35928bfd1..71dd9368ff 100644 --- a/addressbook/inc/class.addressbook_vcal.inc.php +++ b/addressbook/inc/class.addressbook_vcal.inc.php @@ -18,7 +18,7 @@ use EGroupware\Api\Link; /** * Addressbook - vCard parser */ -class addressbook_vcal extends Api\Contacts +class addressbook_vcal extends addressbook_bo { /** * product manufacturer from setSupportedFields (lowercase!) @@ -73,6 +73,7 @@ class addressbook_vcal extends Api\Contacts 'UID' => array('uid'), 'REV' => array('modified'), //'KEY' multivalued with mime-type to export PGP and S/Mime public keys + 'KEY' => array('pubkey'), //set for Apple: 'X-ABSHOWAS' => array('fileas_type'), // Horde vCard class uses uppercase prop-names! ); @@ -310,6 +311,10 @@ class addressbook_vcal extends Api\Contacts break; case 'jpegphoto': + if (empty($value) && ($entry['files'] & Api\Contacts::FILES_BIT_PHOTO)) + { + $value = file_get_contents(Api\Link::vfs_path('addressbook', $entry['id'], Api\Contacts::FILES_PHOTO)); + } if (!empty($value) && (($size < 0) || (strlen($value) < $size))) { @@ -331,6 +336,18 @@ class addressbook_vcal extends Api\Contacts } break; + case 'pubkey': // for now we only export S/Mime publik key, as no device supports PGP + // https://en.wikipedia.org/wiki/VCard (search for "KEY") + if (($value = $this->get_key($entry, false))) + { + $options['TYPE'] = 'SMIME'; + $options['MEDIATYPE'] = 'application/x-x509-user-cert'; + $options['ENCODING'] = $this->version == '3.0' ? 'b' : 'BASE64'; + $value = base64_encode($value); + $hasdata++; + } + break; + case 'cat_id': if (!empty($value) && ($values = /*str_replace(',','\\,',*/$this->get_categories($value)))//) { @@ -970,6 +987,19 @@ class addressbook_vcal extends Api\Contacts } break; + case 'pubkey': + $content = $vcardValues[$vcardKey]['value']; + if(in_array($vcardValues[$vcardKey]['params']['ENCODING'],array('b','B','BASE64'))) + { + $content = base64_decode($content); + } + if ($vcardValues[$vcardKey]['params']['ENCODING'] === 'SMIME') + { + // ignore re-importing of S/Mime pubkey for now, as we might be called for a new contact + continue; + } + break; + case 'note': $contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']); break; diff --git a/addressbook/inc/class.addressbook_zpush.inc.php b/addressbook/inc/class.addressbook_zpush.inc.php index 164340608b..580682b4ed 100644 --- a/addressbook/inc/class.addressbook_zpush.inc.php +++ b/addressbook/inc/class.addressbook_zpush.inc.php @@ -372,6 +372,10 @@ class addressbook_zpush implements activesync_plugin_write, activesync_plugin_se break; case 'jpegphoto': + if (empty($contact[$attr]) && ($contact['files'] & Api\Contacts::FILES_BIT_PHOTO)) + { + $contact[$attr] = file_get_contents(Api\Link::vfs_path('addressbook', $contact['id'], Api\Contacts::FILES_PHOTO)); + } if (!empty($contact[$attr])) $message->$key = base64_encode($contact[$attr]); break;