From 2cffcfbc03dfa4463bdfd72de0341000509bcec3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 23 Aug 2012 22:02:38 +0200 Subject: [PATCH] Permission checking for shared addressbooks/contacts. --- apps/contacts/ajax/contact/addproperty.php | 6 +- apps/contacts/ajax/contact/delete.php | 12 +- apps/contacts/ajax/contact/deleteproperty.php | 6 +- apps/contacts/ajax/contact/list.php | 16 ++- apps/contacts/ajax/contact/saveproperty.php | 7 +- apps/contacts/js/contacts.js | 108 +++++++++++++++--- apps/contacts/lib/share/addressbook.php | 1 + apps/contacts/lib/vcard.php | 44 +++++-- 8 files changed, 163 insertions(+), 37 deletions(-) diff --git a/apps/contacts/ajax/contact/addproperty.php b/apps/contacts/ajax/contact/addproperty.php index 89f7a2bd9a..2b80ebd58b 100644 --- a/apps/contacts/ajax/contact/addproperty.php +++ b/apps/contacts/ajax/contact/addproperty.php @@ -154,8 +154,10 @@ foreach ($parameters as $key=>$element) { } $checksum = md5($vcard->children[$line]->serialize()); -if(!OC_Contacts_VCard::edit($id, $vcard)) { - bailOut($l10n->t('Error adding contact property: '.$name)); +try { + OC_Contacts_VCard::edit($id, $vcard); +} catch(Exception $e) { + bailOut($e->getMessage()); } OCP\JSON::success(array( diff --git a/apps/contacts/ajax/contact/delete.php b/apps/contacts/ajax/contact/delete.php index def98b3670..e73f34f898 100644 --- a/apps/contacts/ajax/contact/delete.php +++ b/apps/contacts/ajax/contact/delete.php @@ -4,6 +4,7 @@ * * @author Jakob Sack * @copyright 2011 Jakob Sack mail@jakobsack.de + * @copyright 2012 Thomas Tanghus (thomas@tanghus.net) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -30,7 +31,14 @@ $id = isset($_POST['id'])?$_POST['id']:null; if(!$id) { bailOut(OC_Contacts_App::$l10n->t('id is not set.')); } -$card = OC_Contacts_App::getContactObject( $id ); -OC_Contacts_VCard::delete($id); +try { + OC_Contacts_VCard::delete($id); +} catch(Exception $e) { + $msg = $e->getMessage(); + OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$msg, + OCP\Util::DEBUG); + OCP\Util::writeLog('contacts', __METHOD__.', id'.$id, OCP\Util::DEBUG); + bailOut($msg); +} OCP\JSON::success(array('data' => array( 'id' => $id ))); diff --git a/apps/contacts/ajax/contact/deleteproperty.php b/apps/contacts/ajax/contact/deleteproperty.php index b76eb19462..b76b6e55ed 100644 --- a/apps/contacts/ajax/contact/deleteproperty.php +++ b/apps/contacts/ajax/contact/deleteproperty.php @@ -40,8 +40,10 @@ if(is_null($line)) { unset($vcard->children[$line]); -if(!OC_Contacts_VCard::edit($id, $vcard)) { - bailOut($l10n->t('Error deleting contact property.')); +try { + OC_Contacts_VCard::edit($id, $vcard); +} catch(Exception $e) { + bailOut($e->getMessage()); } OCP\JSON::success(array( diff --git a/apps/contacts/ajax/contact/list.php b/apps/contacts/ajax/contact/list.php index c5eca292f1..4e2509d8d5 100644 --- a/apps/contacts/ajax/contact/list.php +++ b/apps/contacts/ajax/contact/list.php @@ -41,6 +41,10 @@ foreach($active_addressbooks as $addressbook) { = array('contacts' => array('type' => 'book',)); $contacts_addressbook[$addressbook['id']]['displayname'] = $addressbook['displayname']; + $contacts_addressbook[$addressbook['id']]['permissions'] + = isset($addressbook['permissions']) + ? $addressbook['permissions'] + : '0'; } } @@ -75,10 +79,14 @@ if($contacts_alphabet) { } } $contacts_addressbook[$contact['addressbookid']]['contacts'][] = array( - 'type' => 'contact', - 'id' => $contact['id'], - 'addressbookid' => $contact['addressbookid'], - 'displayname' => htmlspecialchars($display) + 'type' => 'contact', + 'id' => $contact['id'], + 'addressbookid' => $contact['addressbookid'], + 'displayname' => htmlspecialchars($display), + 'permissions' => + isset($contacts_addressbook[$contact['addressbookid']]['permissions']) + ? $contacts_addressbook[$contact['addressbookid']]['permissions'] + : '0', ); } } diff --git a/apps/contacts/ajax/contact/saveproperty.php b/apps/contacts/ajax/contact/saveproperty.php index 296b9ad3b7..7ae183538b 100644 --- a/apps/contacts/ajax/contact/saveproperty.php +++ b/apps/contacts/ajax/contact/saveproperty.php @@ -162,9 +162,10 @@ if(!$value) { } //debug('New checksum: '.$checksum); -if(!OC_Contacts_VCard::edit($id, $vcard)) { - bailOut(OC_Contacts_App::$l10n->t('Error updating contact property.')); - exit(); +try { + OC_Contacts_VCard::edit($id, $vcard); +} catch(Exception $e) { + bailOut($e->getMessage()); } OCP\JSON::success(array('data' => array( diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index a6262349df..09cf26bf7f 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -398,12 +398,32 @@ OC.Contacts={ localLoadContact(newid, bookid); } }, + setEnabled:function(enabled) { + console.log('setEnabled', enabled); + $('.contacts_property,.action').each(function () { + $(this).prop('disabled', !enabled); + OC.Contacts.Card.enabled = enabled; + }); + }, doExport:function() { document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + this.id; }, editNew:function(){ // add a new contact - this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = ''; - OC.Contacts.Card.add(';;;;;', '', '', true); + var book = $('#contacts h3.active'); + var permissions = parseInt(book.data('permissions')); + if(permissions == 0 + || permissions & OC.Share.PERMISSION_UPDATE + || permissions & OC.Share.PERMISSION_DELETE) { + with(this) { + delete id; delete fn; delete fullname; delete givname; delete famname; + delete addname; delete honpre; delete honsuf; + } + this.bookid = book.data('id'); + OC.Contacts.Card.add(';;;;;', '', '', true); + } else { + OC.dialogs.alert(t('contacts', 'You do not have permission to add contacts to ') + + book.text() + '. ' + t('contacts', 'Please select one of your own address books.'), t('contacts', 'Permission error')); + } return false; }, add:function(n, fn, aid, isnew){ // add a new contact @@ -497,11 +517,16 @@ OC.Contacts={ OC.Contacts.notify({ data:curlistitem, message:t('contacts','Click to undo deletion of "') + curlistitem.find('a').text() + '"', - timeout:5, + //timeout:5, timeouthandler:function(contact) { console.log('timeout'); - OC.Contacts.Card.doDelete(contact.data('id'), true); - delete contact; + OC.Contacts.Card.doDelete(contact.data('id'), true, function(res) { + if(!res) { + OC.Contacts.Contacts.insertContact({contact:contact}); + } else { + delete contact; + } + }); }, clickhandler:function(contact) { OC.Contacts.Contacts.insertContact({contact:contact}); @@ -510,7 +535,7 @@ OC.Contacts={ } }); }, - doDelete:function(id, removeFromQueue) { + doDelete:function(id, removeFromQueue, cb) { var updateQueue = function(id, remove) { if(removeFromQueue) { OC.Contacts.Contacts.deletionQueue.splice(OC.Contacts.Contacts.deletionQueue.indexOf(parseInt(id)), 1); @@ -523,14 +548,23 @@ OC.Contacts={ if(OC.Contacts.Contacts.deletionQueue.indexOf(parseInt(id)) == -1 && removeFromQueue) { console.log('returning'); updateQueue(id, removeFromQueue); + if(typeof cb == 'function') { + cb(true); + } return; } - $.post(OC.filePath('contacts', 'ajax', 'contact/delete.php'),{'id':id},function(jsondata) { + $.post(OC.filePath('contacts', 'ajax', 'contact/delete.php'), {'id':id},function(jsondata) { if(jsondata.status == 'error'){ - OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); + OC.Contacts.notify({message:jsondata.data.message}); + if(typeof cb == 'function') { + cb(false); + } } updateQueue(id, removeFromQueue); }); + if(typeof cb == 'function') { + cb(true); + } }, loadContact:function(jsondata, bookid){ this.data = jsondata; @@ -563,6 +597,11 @@ OC.Contacts={ $('#contact_note').hide(); $('#contacts_propertymenu_dropdown a[data-type="NOTE"]').parent().show(); } + var permissions = OC.Contacts.Card.permissions = parseInt($('#contacts ul[data-id="' + bookid + '"]').data('permissions')); + console.log('permissions', permissions); + this.setEnabled(permissions == 0 + || permissions & OC.Share.PERMISSION_UPDATE + || permissions & OC.Share.PERMISSION_DELETE); }, loadSingleProperties:function() { var props = ['BDAY', 'NICKNAME', 'ORG', 'URL', 'CATEGORIES']; @@ -757,6 +796,13 @@ OC.Contacts={ console.log('Saving: ' + q); $(obj).attr('disabled', 'disabled'); $.post(OC.filePath('contacts', 'ajax', 'contact/saveproperty.php'),q,function(jsondata){ + if(!jsondata) { + OC.dialogs.alert(t('contacts', 'Unknown error. Please check logs.'), t('contacts', 'Error')); + OC.Contacts.loading(obj, false); + $(obj).removeAttr('disabled'); + OC.Contacts.Card.update({cid:OC.Contacts.Card.id}); + return false; + } if(jsondata.status == 'success'){ container.data('checksum', jsondata.data.checksum); OC.Contacts.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum); @@ -768,6 +814,7 @@ OC.Contacts={ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); OC.Contacts.loading(obj, false); $(obj).removeAttr('disabled'); + OC.Contacts.Card.update({cid:OC.Contacts.Card.id}); return false; } },'json'); @@ -787,12 +834,16 @@ OC.Contacts={ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); OC.Contacts.loading(obj, false); $(obj).removeAttr('disabled'); + OC.Contacts.Card.update({cid:OC.Contacts.Card.id}); return false; } },'json'); } }, addProperty:function(type) { + if(!this.enabled) { + return; + } switch (type) { case 'NOTE': $('#contacts_propertymenu_dropdown a[data-type="'+type+'"]').parent().hide(); @@ -836,6 +887,9 @@ OC.Contacts={ }, deleteProperty:function(obj, type) { console.log('deleteProperty'); + if(!this.enabled) { + return; + } OC.Contacts.loading(obj, true); var checksum = OC.Contacts.checksumFor(obj); if(checksum) { @@ -887,6 +941,9 @@ OC.Contacts={ } }, editName:function() { + if(!this.enabled) { + return; + } var params = {id: this.id}; /* Initialize the name edit dialog */ if($('#edit_name_dialog').dialog('isOpen') == true) { @@ -922,6 +979,9 @@ OC.Contacts={ } }, saveName:function(dlg) { + if(!this.enabled) { + return; + } //console.log('saveName, id: ' + this.id); var n = new Array($(dlg).find('#fam').val().strip_tags(),$(dlg).find('#giv').val().strip_tags(),$(dlg).find('#add').val().strip_tags(),$(dlg).find('#pre').val().strip_tags(),$(dlg).find('#suf').val().strip_tags()); this.famname = n[0]; @@ -1010,6 +1070,9 @@ OC.Contacts={ return false; }, editAddress:function(obj, isnew){ + if(!this.enabled) { + return; + } var container = undefined; var params = {id: this.id}; if(obj === 'new') { @@ -1135,6 +1198,9 @@ OC.Contacts={ } }, saveAddress:function(dlg, obj, isnew){ + if(!this.enabled) { + return; + } if(isnew) { container = $('#addresses dl').last(); obj = container.find('input').first(); @@ -1177,6 +1243,9 @@ OC.Contacts={ container.find('.addresslist').html(adrtxt); }, uploadPhoto:function(filelist) { + if(!this.enabled) { + return; + } if(!filelist) { OC.dialogs.alert(t('contacts','No files selected for upload.'), t('contacts', 'Error')); return; @@ -1255,6 +1324,9 @@ OC.Contacts={ this.loadPhotoHandlers() }, editCurrentPhoto:function(){ + if(!this.enabled) { + return; + } $.getJSON(OC.filePath('contacts', 'ajax', 'currentphoto.php'),{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); @@ -1268,6 +1340,9 @@ OC.Contacts={ }); }, editPhoto:function(id, tmpkey){ + if(!this.enabled) { + return; + } //alert('editPhoto: ' + tmpkey); $.getJSON(OC.filePath('contacts', 'ajax', 'cropphoto.php'),{'tmpkey':tmpkey,'id':this.id, 'requesttoken':requesttoken},function(jsondata){ if(jsondata.status == 'success'){ @@ -1284,7 +1359,10 @@ OC.Contacts={ $('#edit_photo_dialog').dialog('open'); } }, - savePhoto:function(){ + savePhoto:function() { + if(!this.enabled) { + return; + } var target = $('#crop_target'); var form = $('#cropform'); var wrapper = $('#contacts_details_photo_wrapper'); @@ -1719,11 +1797,15 @@ OC.Contacts={ firstrun = true; if($('#contacts h3').length == 0) { $('#contacts').html('

'+book.displayname+'

'); + + b + '" data-permissions="' + book.permissions + '">' + book.displayname + + ''); } else { - if(!$('#contacts h3[data-id="'+b+'"]').length) { - var item = $('

' - + book.displayname+'

') + if(!$('#contacts h3[data-id="' + b + '"]').length) { + var item = $('

' + + book.displayname+'

'); var added = false; $('#contacts h3').each(function(){ if ($(this).text().toLowerCase() > book.displayname.toLowerCase()) { diff --git a/apps/contacts/lib/share/addressbook.php b/apps/contacts/lib/share/addressbook.php index 0c90470d37..d35f0ce9ae 100644 --- a/apps/contacts/lib/share/addressbook.php +++ b/apps/contacts/lib/share/addressbook.php @@ -73,6 +73,7 @@ class OC_Share_Backend_Addressbook implements OCP\Share_Backend_Collection { $addressbook = OC_Contacts_Addressbook::find($item['item_source']); if ($addressbook) { $addressbook['displayname'] = $item['item_target']; + $addressbook['permissions'] = $item['permissions']; $addressbooks[] = $addressbook; } } diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 58d78875af..cee9c640cf 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -405,7 +405,7 @@ class OC_Contacts_VCard{ if ($addressbook['userid'] != OCP\User::getUser()) { $sharedContact = OCP\Share::getItemSharedWithBySource('contact', $id, OCP\Share::FORMAT_NONE, null, true); if (!$sharedContact || !($sharedContact['permissions'] & OCP\Share::PERMISSION_UPDATE)) { - return false; + throw new Exception(OC_Contacts_App::$l10n->t('You do not have the permissions to edit this contact.')); } } OC_Contacts_App::loadCategoriesFromVCard($card); @@ -423,7 +423,8 @@ class OC_Contacts_VCard{ try { $result = $stmt->execute(array($fn,$data,time(),$id)); } catch(Exception $e) { - OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); + OCP\Util::writeLog('contacts', __METHOD__.', exception: ' + . $e->getMessage(), OCP\Util::ERROR); OCP\Util::writeLog('contacts', __METHOD__.', id'.$id, OCP\Util::DEBUG); return false; } @@ -444,10 +445,21 @@ class OC_Contacts_VCard{ $oldcard = self::findWhereDAVDataIs($aid, $uri); $card = OC_VObject::parse($data); if(!$card) { - OCP\Util::writeLog('contacts', __METHOD__.', Unable to parse VCARD, uri: '.$uri, OCP\Util::ERROR); + OCP\Util::writeLog('contacts', __METHOD__. + ', Unable to parse VCARD, uri: '.$uri, OCP\Util::ERROR); + return false; + } + try { + self::edit($oldcard['id'], $card); + return true; + } catch(Exception $e) { + OCP\Util::writeLog('contacts', __METHOD__.', exception: ' + . $e->getMessage() . ', ' + . OCP\USER::getUser(), OCP\Util::ERROR); + OCP\Util::writeLog('contacts', __METHOD__.', uri' + . $uri, OCP\Util::DEBUG); return false; } - return self::edit($oldcard['id'], $card); } /** @@ -462,18 +474,28 @@ class OC_Contacts_VCard{ } $addressbook = OC_Contacts_Addressbook::find($card['addressbookid']); if ($addressbook['userid'] != OCP\User::getUser()) { - $sharedContact = OCP\Share::getItemSharedWithBySource('contact', $id, OCP\Share::FORMAT_NONE, null, true); - if (!$sharedContact || !($sharedContact['permissions'] & OCP\Share::PERMISSION_DELETE)) { - return false; + $sharedContact = OCP\Share::getItemSharedWithBySource('contact', + $id, OCP\Share::FORMAT_NONE, null, true); + if (!$sharedContact + || !($sharedContact['permissions'] & OCP\Share::PERMISSION_DELETE)) { + throw new Exception( + OC_Contacts_App::$l10n->t( + 'You do not have the permissions to delete this contact.' + ) + ); } } - OC_Hook::emit('OC_Contacts_VCard', 'pre_deleteVCard', array('aid' => null, 'id' => $id, 'uri' => null)); - $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*contacts_cards WHERE id = ?' ); + OC_Hook::emit('OC_Contacts_VCard', 'pre_deleteVCard', + array('aid' => null, 'id' => $id, 'uri' => null) + ); + $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*contacts_cards WHERE id = ?'); try { $stmt->execute(array($id)); } catch(Exception $e) { - OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); - OCP\Util::writeLog('contacts', __METHOD__.', id: '.$id, OCP\Util::DEBUG); + OCP\Util::writeLog('contacts', __METHOD__. + ', exception: ' . $e->getMessage(), OCP\Util::ERROR); + OCP\Util::writeLog('contacts', __METHOD__.', id: ' + . $id, OCP\Util::DEBUG); return false; }