fix lost picture when pubkeys get updated/added via mail account dialog and vCard, CardDAV or eSync export

This commit is contained in:
Ralf Becker 2017-09-19 15:30:13 +02:00
parent c673fac96b
commit 3d57827d8c
3 changed files with 69 additions and 20 deletions

View File

@ -251,6 +251,7 @@ class addressbook_bo extends Api\Contacts
{ {
$contact['pubkey'] = preg_replace($key_regexp, $key, $contact['pubkey']); $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 ($this->check_perms(Acl::EDIT, $contact) && $this->save($contact))
{ {
if ($path) if ($path)
@ -283,7 +284,7 @@ class addressbook_bo extends Api\Contacts
* *
* EMail addresses are lowercased to make search case-insensitive * 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 * @param boolean $pgp true: PGP, false: S/Mime public keys
* @return array email|account_id => key pairs * @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 (!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(); $criteria = $result = array();
foreach($recipients as &$recipient) 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'), foreach($this->search($criteria, array('account_id', 'contact_email', 'contact_pubkey', 'contact_id'),
'', '', '', false, 'OR', false, null) as $contact) '', '', '', false, 'OR', false, null) as $contact)
{ {
$matches = null;
// first check for file and second for pubkey field (LDAP, AD or old SQL) // 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))) && if (($content = $this->get_key($contact, $pgp)))
preg_match($key_regexp, $content, $matches) ||
preg_match($key_regexp, $contact['pubkey'], $matches))
{ {
$contact['email'] = strtolower($contact['email']); $contact['email'] = strtolower($contact['email']);
if (empty($criteria['account_id']) || in_array($contact['email'], $recipients)) if (empty($criteria['account_id']) || in_array($contact['email'], $recipients))
{ {
$result[$contact['email']] = $matches[0]; $result[$contact['email']] = $content;
} }
else else
{ {
$result[$contact['account_id']] = $matches[0]; $result[$contact['account_id']] = $content;
} }
} }
} }
return $result; 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 * Search addressbook for SMIME Certificate keys of given recipients
* *

View File

@ -18,7 +18,7 @@ use EGroupware\Api\Link;
/** /**
* Addressbook - vCard parser * Addressbook - vCard parser
*/ */
class addressbook_vcal extends Api\Contacts class addressbook_vcal extends addressbook_bo
{ {
/** /**
* product manufacturer from setSupportedFields (lowercase!) * product manufacturer from setSupportedFields (lowercase!)
@ -73,6 +73,7 @@ class addressbook_vcal extends Api\Contacts
'UID' => array('uid'), 'UID' => array('uid'),
'REV' => array('modified'), 'REV' => array('modified'),
//'KEY' multivalued with mime-type to export PGP and S/Mime public keys //'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! //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; break;
case 'jpegphoto': 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) && if (!empty($value) &&
(($size < 0) || (strlen($value) < $size))) (($size < 0) || (strlen($value) < $size)))
{ {
@ -331,6 +336,18 @@ class addressbook_vcal extends Api\Contacts
} }
break; 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': case 'cat_id':
if (!empty($value) && ($values = /*str_replace(',','\\,',*/$this->get_categories($value)))//) if (!empty($value) && ($values = /*str_replace(',','\\,',*/$this->get_categories($value)))//)
{ {
@ -970,6 +987,19 @@ class addressbook_vcal extends Api\Contacts
} }
break; 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': case 'note':
$contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']); $contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']);
break; break;

View File

@ -372,6 +372,10 @@ class addressbook_zpush implements activesync_plugin_write, activesync_plugin_se
break; break;
case 'jpegphoto': 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]); if (!empty($contact[$attr])) $message->$key = base64_encode($contact[$attr]);
break; break;