From 1fe1ac022f0755d73c62bac86f1b54fdbd6b50f5 Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Fri, 25 May 2012 18:26:09 -0600 Subject: [PATCH 1/8] Support relayable_retractions that are relayed to us by the top-level post owner --- include/delivery.php | 1 + include/diaspora.php | 46 +++++++++++++++++++++++++++++++++++--------- include/notifier.php | 1 + 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index 32943d5dab..0e40e3db72 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -113,6 +113,7 @@ function delivery_run($argv, $argc){ $uid = $r[0]['uid']; $updated = $r[0]['edited']; + // The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up if(! $parent_id) continue; diff --git a/include/diaspora.php b/include/diaspora.php index f7c2c5e8ec..8b8050a614 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -83,6 +83,9 @@ function diaspora_dispatch($importer,$msg) { elseif($xmlbase->signed_retraction) { $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg); } + elseif($xmlbase->relayable_retraction) { + $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg); + } elseif($xmlbase->photo) { $ret = diaspora_photo($importer,$xmlbase->photo,$msg); } @@ -677,7 +680,7 @@ function diaspora_post($importer,$xml) { return; } - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -844,7 +847,7 @@ function diaspora_reshare($importer,$xml) { $prefix = '♲ ' . $details . "\n"; - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -948,7 +951,7 @@ function diaspora_asphoto($importer,$xml) { return; } - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -1783,28 +1786,53 @@ function diaspora_signed_retraction($importer,$xml,$msg) { $type = notags(unxmlify($xml->target_type)); $sig = notags(unxmlify($xml->target_author_signature)); + $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) { logger('diaspora_signed_retraction: no contact'); return; } - // this may not yet work for comments. Need to see how the relaying works - // and figure out who signs it. - $signed_data = $guid . ';' . $type ; $sig = base64_decode($sig); - $key = $msg['key']; + if(strcasecmp($diaspora_handle,$msg['author']) == 0) { + $person = $contact; + $key = $msg['key']; + } + else { + $person = find_diaspora_person_by_handle($diaspora_handle); + + if(is_array($person) && x($person,'pubkey')) + $key = $person['pubkey']; + else { + logger('diaspora_signed_retraction: unable to find author details'); + return; + } + } if(! rsa_verify($signed_data,$sig,$key,'sha256')) { - logger('diaspora_signed_retraction: owner verification failed.' . print_r($msg,true)); + logger('diaspora_signed_retraction: retraction-owner verification failed.' . print_r($msg,true)); return; } - if($type === 'StatusMessage') { + if($parent_author_signature) { + $owner_signed_data = $guid . ';' . $type ; + + $parent_author_signature = base64_decode($parent_author_signature); + + $key = $msg['key']; + + if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_signed_retraction: failed to verify person relaying the retraction (e.g. owner of a post relaying a retracted comment'); + return; + } + } + + if($type === 'StatusMessage' || $type === 'Comment') { $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", dbesc($guid), intval($importer['uid']) diff --git a/include/notifier.php b/include/notifier.php index 070e7a4361..47ad29310f 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -125,6 +125,7 @@ function notifier_run($argv, $argc){ $uid = $r[0]['uid']; $updated = $r[0]['edited']; + // The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up if(! $parent_id) return; From c0af6dbb1a5507dcf0fffaf13b42cfd71b0d0c50 Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Thu, 31 May 2012 19:40:12 -0600 Subject: [PATCH 2/8] Implement relaying of relayable_retractions Also: some whitespace cleanup, fix Diaspora parent DB query --- include/delivery.php | 4 +- include/diaspora.php | 151 ++++++++++++++++++++----- include/items.php | 31 ++++- include/notifier.php | 15 ++- mod/item.php | 10 +- update.php | 5 +- view/diaspora_relay_retraction.tpl | 10 ++ view/diaspora_relayable_retraction.tpl | 11 ++ 8 files changed, 194 insertions(+), 43 deletions(-) create mode 100644 view/diaspora_relay_retraction.tpl create mode 100644 view/diaspora_relayable_retraction.tpl diff --git a/include/delivery.php b/include/delivery.php index 0e40e3db72..62c9f92020 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -509,7 +509,7 @@ function delivery_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($target_item['verb'] !== ACTIVITY_LIKE)) { + elseif(($target_item['deleted']) && ($top_level) && ($target_item['verb'] !== ACTIVITY_LIKE)) { logger('delivery: diaspora retract: ' . $loc); // diaspora delete, diaspora_send_retraction($target_item,$owner,$contact,$public_message); @@ -519,7 +519,7 @@ function delivery_run($argv, $argc){ logger('delivery: diaspora relay: ' . $loc); - // we are the relay - send comments, likes and unlikes to our conversants + // we are the relay - send comments, likes, unlikes and relayable_retractions to our conversants diaspora_send_relay($target_item,$owner,$contact,$public_message); break; } diff --git a/include/diaspora.php b/include/diaspora.php index 8b8050a614..584be5ef26 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -680,7 +680,7 @@ function diaspora_post($importer,$xml) { return; } - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -847,7 +847,7 @@ function diaspora_reshare($importer,$xml) { $prefix = '♲ ' . $details . "\n"; - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -951,7 +951,7 @@ function diaspora_asphoto($importer,$xml) { return; } - // allocate a guid on our system - we aren't fixing any collisions. + // allocate a guid on our system - we aren't fixing any collisions. // we're ignoring them $g = q("select * from guid where guid = '%s' limit 1", @@ -1168,7 +1168,22 @@ function diaspora_comment($importer,$xml,$msg) { ); } - if(($parent_item['origin']) && (! $parent_author_signature)) { + if(($parent_item['origin']) && (! $parent_author_signature)) { if(($parent_item['origin']) && (! $parent_author_signature)) { + q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($message_id), + dbesc($author_signed_data), + dbesc(base64_encode($author_signature)), + dbesc($diaspora_handle) + ); + + // if the message isn't already being relayed, notify others + // the existence of parent_author_signature means the parent_author or owner + // is already relaying. + + proc_run('php','include/notifier.php','comment',$message_id); + } + + q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($author_signed_data), @@ -1797,7 +1812,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) { $signed_data = $guid . ';' . $type ; - $sig = base64_decode($sig); + $sig_decode = base64_decode($sig); if(strcasecmp($diaspora_handle,$msg['author']) == 0) { $person = $contact; @@ -1814,22 +1829,21 @@ function diaspora_signed_retraction($importer,$xml,$msg) { } } - if(! rsa_verify($signed_data,$sig,$key,'sha256')) { + if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) { logger('diaspora_signed_retraction: retraction-owner verification failed.' . print_r($msg,true)); return; } if($parent_author_signature) { - $owner_signed_data = $guid . ';' . $type ; - $parent_author_signature = base64_decode($parent_author_signature); $key = $msg['key']; - if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { logger('diaspora_signed_retraction: failed to verify person relaying the retraction (e.g. owner of a post relaying a retracted comment'); return; } + } if($type === 'StatusMessage' || $type === 'Comment') { @@ -1839,10 +1853,36 @@ function diaspora_signed_retraction($importer,$xml,$msg) { ); if(count($r)) { if(link_compare($r[0]['author-link'],$contact['url'])) { - q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d limit 1", + q("update item set `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' where `id` = %d limit 1", dbesc(datetime_convert()), intval($r[0]['id']) ); + + // Now check if the retraction needs to be relayed by us + // + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select origin from item where parent = %d and id = %d limit 1", + $r[0]['parent'], + $r[0]['parent'] + ); + if(count($p)) { + if(($p[0]['origin']) && (! $parent_author_signature)) { + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + $r[0]['id'], + dbesc($signed_data), + dbesc($sig), + dbesc($diaspora_handle) + ); + + // the existence of parent_author_signature would have meant the parent_author or owner + // is already relaying. + logger('diaspora_signed_retraction: relaying relayable_retraction'); + + proc_run('php','include/notifier.php','relayable_retraction',$r[0]['id']); + } + } } } } @@ -2136,10 +2176,28 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { +// I think the first comment or like on a post whose home is our Friendica server is saved as an item +// as the top-level post owner's contact for writer of the comment or post. Thus, the "uid" +// on the item is `user`.`id` of the top-level post owner. That user is passed to this function +// as "$owner." +// +// I'm assuming for now that "$owner" will be the user of the top-level post for retractions too. Be +// aware that another reasonable possibility is that it's the "$owner" of the deleted comment. + +// TODO +// CHECK 1. If we receive a retraction from Diaspora to be relayed by us, we need to insert the signature +// into the DB and call notifier.php +// CHECK 2. diaspora_send_retraction() needs to be modified to send +// Diaspora a retraction for it to relay when appropriate +// CHECK 3. notifier.php (and delivery.php?) need to be modified to call the right functions for the right +// retraction situation +// 4. If possible, modify notifier.php (and delivery.php?) to remove the relayable retraction's signature +// from the DB after finishing with relaying retractions + $a = get_app(); - $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); $theiraddr = $contact['addr']; @@ -2155,29 +2213,42 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { else return; + $like = false; + $relay_retract = false; + $sql_sign_id = 'iid'; if($item['verb'] === ACTIVITY_LIKE) { $tpl = get_markup_template('diaspora_like_relay.tpl'); $like = true; $target_type = 'Post'; $positive = (($item['deleted']) ? 'false' : 'true'); } - else { + elseif(! $item['deleted']) { $tpl = get_markup_template('diaspora_comment_relay.tpl'); - $like = false; + } + else { + $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); + $relay_retract = true; + $sql_sign_id = 'retract_iid'; + $target_type = 'Comment'; } $body = $item['body']; $text = html_entity_decode(bb2diaspora($body)); + // fetch the original signature if somebody sent the post to us to relay + // // If we are relaying for a reply originating on our own account, there wasn't a 'send to relay' // action. It wasn't needed. In that case create the original signature and the // owner (parent author) signature + // Note that mod/item.php seems to take care of creating a signature for Diaspora for replies + // created on our own account + // // comments from other networks will be relayed under our name, with a brief // preamble to describe what's happening and noting the real author - $r = q("select * from sign where iid = %d limit 1", + $r = q("select * from sign where " . $sql_sign_id . " = %d limit 1", intval($item['id']) ); if(count($r)) { @@ -2196,29 +2267,39 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $prefix = sprintf( t('[Relayed] Comment authored by %s from network %s'), '['. $item['author-name'] . ']' . '(' . $item['author-link'] . ')', network_to_name($itemcontact['network'])) . "\n"; + // "$body" was assigned to "$text" above. It isn't used after that, so I don't think + // the following change will do anything $body = $prefix . $body; + + // I think this comment will fail upon reaching Diaspora, because "$signed_text" is not defined } } else { + // I'm confused about this "else." Since it sets "$handle = $myaddr," it seems like it should be for the case + // where the top-level post owner commented on his own post, i.e. "$itemcontact[0]['self']" is true. But it's + // positioned to be for the case where "count($itemcontact)" is 0. + + $handle = $myaddr; if($like) - $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $myaddr; + $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $handle; + elseif($relay_retract) + $signed_text = $item['guid'] . ';' . $target_type; else - $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr; + $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle; $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')); - q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + q("insert into sign (`" . $sql_sign_id . "`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($item['id']), dbesc($signed_text), - dbesc(base64_encode($authorsig)), - dbesc($myaddr) + dbesc($authorsig), + dbesc($handle) ); - $handle = $myaddr; } } - // sign it + // sign it with the top-level owner's signature $parentauthorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')); @@ -2226,14 +2307,15 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { '$guid' => xmlify($item['guid']), '$parent_guid' => xmlify($parent_guid), '$target_type' =>xmlify($target_type), - '$authorsig' => xmlify($orig_sign['signature']), + '$authorsig' => xmlify($authorsig), '$parentsig' => xmlify($parentauthorsig), '$body' => xmlify($text), '$positive' => xmlify($positive), '$handle' => xmlify($handle) )); - logger('diaspora_relay_comment: base message: ' . $msg, LOGGER_DATA); + logger('diaspora_send_relay: base message: ' . $msg, LOGGER_DATA); + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); @@ -2248,14 +2330,25 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { $a = get_app(); $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $signed_text = $item['guid'] . ';' . 'StatusMessage'; + // Check if the retraction is for a top-level post, or whether it's for a comment + if( $item['id'] !== $item['parent'] ) { + + $tpl = get_markup_template('diaspora_relay_retraction.tpl'); + $target_type = 'Comment'; + } + else { + + $tpl = get_markup_template('diaspora_signed_retract.tpl'); + $target_type = 'StatusMessage'; + } + + $signed_text = $item['guid'] . ';' . $target_type; - $tpl = get_markup_template('diaspora_signed_retract.tpl'); $msg = replace_macros($tpl, array( - '$guid' => $item['guid'], - '$type' => 'StatusMessage', - '$handle' => $myaddr, - '$signature' => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')) + '$guid' => xmlify($item['guid']), + '$type' => xmlify($target_type), + '$handle' => xmlify($myaddr), + '$signature' => xmlify(base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'))) )); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); diff --git a/include/items.php b/include/items.php index 0ed16217fa..8858ca64fa 100644 --- a/include/items.php +++ b/include/items.php @@ -3278,7 +3278,36 @@ function drop_item($id,$interactive = true) { q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1", intval($r[0]['id']) ); - } + } + + // Add a relayable_retraction signature for Diaspora. Note that we can't add a target_author_signature + // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting + // the comment, that means we're the home of the post, and Diaspora will only + // check the parent_author_signature of retractions that it doesn't have to relay further + if( strcmp($item['type'], 'activity') != 0) { + $signed_text = $item['guid'] . ';' . 'Comment'; + + if(local_user() == $item['uid']) { + + $handle = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256')); + } + else { + $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", + $item['contact-id'] + ); + if(count($r)) + $handle = $r['nick'] . '@' . substr($r['url'], strpos($r['url'],'://') + 3, strpos($r['url'],'/profile') - 1); + } + + if(isset($handle) + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($item['id']), + dbesc($signed_text), + dbesc($authorsig), + dbesc($handle) + ); + } } $drop_id = intval($item['id']); diff --git a/include/notifier.php b/include/notifier.php index 47ad29310f..68f230a05f 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -597,7 +597,7 @@ function notifier_run($argv, $argc){ break; case NETWORK_OSTATUS: - // Do not send to otatus if we are not configured to send to public networks + // Do not send to ostatus if we are not configured to send to public networks if($owner['prvnets']) break; if(get_config('system','ostatus_disabled') || get_config('system','dfrn_only')) @@ -738,8 +738,8 @@ function notifier_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($target_item['verb'] !== ACTIVITY_LIKE)) { - // diaspora delete, + elseif(($target_item['deleted']) && ($top_level || $followup) && ($target_item['verb'] !== ACTIVITY_LIKE)) { + // diaspora delete, including relayable_retractions that need to be relayed diaspora_send_retraction($target_item,$owner,$contact); break; } @@ -749,7 +749,7 @@ function notifier_run($argv, $argc){ break; } elseif($target_item['parent'] != $target_item['id']) { - // we are the relay - send comments, likes and unlikes to our conversants + // we are the relay - send comments, likes, unlikes and relayable_retractions to our conversants diaspora_send_relay($target_item,$owner,$contact); break; } @@ -859,6 +859,13 @@ function notifier_run($argv, $argc){ } + // If the item was deleted, clean up the `sign` table + if($target_item['deleted']) { + $r = q("DELETE FROM sign where `retract_iid` = %d", + intval($target_item['id']) + ); + } + logger('notifier: calling hooks', LOGGER_DEBUG); if($normal_mode) diff --git a/mod/item.php b/mod/item.php index 497cf5daa2..c1c0b14ec6 100644 --- a/mod/item.php +++ b/mod/item.php @@ -737,16 +737,16 @@ function item_post(&$a) { if($datarray['verb'] === ACTIVITY_LIKE) $signed_text = $datarray['guid'] . ';' . 'Post' . ';' . $parent_item['guid'] . ';' . 'true' . ';' . $myaddr; else - $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $myaddr; + $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $myaddr; $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256')); q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), - dbesc($signed_text), - dbesc(base64_encode($authorsig)), - dbesc($myaddr) - ); + dbesc($signed_text), + dbesc(base64_encode($authorsig)), + dbesc($myaddr) + ); } } else { diff --git a/update.php b/update.php index 1b2098e6eb..e1a554533c 100644 --- a/update.php +++ b/update.php @@ -1137,8 +1137,8 @@ INDEX ( `username` ) } function update_1133() { -q("ALTER TABLE `user` ADD `unkmail` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `blocktags` , ADD INDEX ( `unkmail` ) "); -q("ALTER TABLE `user` ADD `cntunkmail` INT NOT NULL DEFAULT '10' AFTER `unkmail` , ADD INDEX ( `cntunkmail` ) "); +q("ALTER TABLE `user` ADD `unkmail` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `blocktags` , ADD INDEX ( `unkmail` ) "); +q("ALTER TABLE `user` ADD `cntunkmail` INT NOT NULL DEFAULT '10' AFTER `unkmail` , ADD INDEX ( `cntunkmail` ) "); q("ALTER TABLE `mail` ADD `unknown` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `replied` , ADD INDEX ( `unknown` ) "); } @@ -1274,4 +1274,5 @@ function update_1146() { return UPDATE_SUCCESS ; } +//ALTER TABLE `sign` MODIFY column int Default '10'; diff --git a/view/diaspora_relay_retraction.tpl b/view/diaspora_relay_retraction.tpl new file mode 100644 index 0000000000..e76c7c6c5e --- /dev/null +++ b/view/diaspora_relay_retraction.tpl @@ -0,0 +1,10 @@ + + + + $type + $guid + $signature + $handle + + + diff --git a/view/diaspora_relayable_retraction.tpl b/view/diaspora_relayable_retraction.tpl new file mode 100644 index 0000000000..27936f7f3b --- /dev/null +++ b/view/diaspora_relayable_retraction.tpl @@ -0,0 +1,11 @@ + + + + $target_type + $guid + $parentauthorsig + $authorsig + $handle + + + From b000088ded0d0f677114da0af1c5ea6436a97560 Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Fri, 1 Jun 2012 09:07:51 -0600 Subject: [PATCH 3/8] prepare to implement database update --- update.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/update.php b/update.php index e1a554533c..9d534a127a 100644 --- a/update.php +++ b/update.php @@ -1274,5 +1274,15 @@ function update_1146() { return UPDATE_SUCCESS ; } -//ALTER TABLE `sign` MODIFY column int Default '10'; +/* +function update_xxxx() { + $r1 = q("ALTER TABLE `sign` MODIFY `iid` SET DEFAULT '0'"); + $r2 = q("ALTER TABLE `sign` ADD `retract_iid` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `iid`"); + $r3 = q("ALTER TABLE `sign` ADD INDEX ( `retract_iid` )"); + if((! $r1) || (! $r2) || (! $r3)) + return UPDATE_FAILED ; + return UPDATE_SUCCESS ; +} +*/ +// dump DB schema: mysqldump -d -h localhost -u root -pmypassword databasename > dumpfile.sql From 77962aa79df5671e206635cc6980e4b1ac969bf9 Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Sat, 2 Jun 2012 16:11:31 -0600 Subject: [PATCH 4/8] Fix bugs in the retraction code Currently, the following seems to be the functional status: For a Diaspora top-level post: Friendica comments show up AND delete Diaspora comments show up AND delete for top-level owner Diaspora comments show up for non-owner Diaspora comments sometimes don't delete for non-owner -> Appears to be Diaspora's fault, as a "not a valid object" error shows up in the log Friendica likes show up, but can't unlike (Friendica doesn't even message Diaspora) Diaspora likes show up Diaspora non-owner can't unlike -> Same as comments, seems to be Diaspora's fault For a Friendica top-level post: Friendica comments show up AND delete Diaspora comments show up AND delete Friendica likes don't show up in Diaspora sometimes Friendica doesn't even message Diaspora for unlikes (sometimes?) Diaspora likes and unlikes work --- include/delivery.php | 4 +-- include/diaspora.php | 46 ++++++-------------------- include/items.php | 46 +++++++++++++------------- include/notifier.php | 4 +-- update.php | 2 +- view/diaspora_like_relay.tpl | 4 +-- view/diaspora_relayable_retraction.tpl | 2 +- 7 files changed, 42 insertions(+), 66 deletions(-) mode change 100644 => 100755 view/diaspora_like_relay.tpl mode change 100644 => 100755 view/diaspora_relayable_retraction.tpl diff --git a/include/delivery.php b/include/delivery.php index 62c9f92020..235b766c5f 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -509,13 +509,13 @@ function delivery_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($top_level) && ($target_item['verb'] !== ACTIVITY_LIKE)) { + elseif(($target_item['deleted']) && ($target_item['uri'] === $target_item['parent-uri']) && ($target_item['verb'] !== ACTIVITY_LIKE)) { logger('delivery: diaspora retract: ' . $loc); // diaspora delete, diaspora_send_retraction($target_item,$owner,$contact,$public_message); break; } - elseif($target_item['parent'] != $target_item['id']) { + elseif($target_item['uri'] !== $target_item['parent-uri']) { logger('delivery: diaspora relay: ' . $loc); diff --git a/include/diaspora.php b/include/diaspora.php index 584be5ef26..10c56564b7 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1168,22 +1168,7 @@ function diaspora_comment($importer,$xml,$msg) { ); } - if(($parent_item['origin']) && (! $parent_author_signature)) { if(($parent_item['origin']) && (! $parent_author_signature)) { - q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - intval($message_id), - dbesc($author_signed_data), - dbesc(base64_encode($author_signature)), - dbesc($diaspora_handle) - ); - - // if the message isn't already being relayed, notify others - // the existence of parent_author_signature means the parent_author or owner - // is already relaying. - - proc_run('php','include/notifier.php','comment',$message_id); - } - - + if(($parent_item['origin']) && (! $parent_author_signature)) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($author_signed_data), @@ -1846,7 +1831,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) { } - if($type === 'StatusMessage' || $type === 'Comment') { + if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') { $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", dbesc($guid), intval($importer['uid']) @@ -1854,6 +1839,7 @@ function diaspora_signed_retraction($importer,$xml,$msg) { if(count($r)) { if(link_compare($r[0]['author-link'],$contact['url'])) { q("update item set `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '' , `title` = '' where `id` = %d limit 1", + dbesc(datetime_convert()), dbesc(datetime_convert()), intval($r[0]['id']) ); @@ -2184,16 +2170,6 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { // I'm assuming for now that "$owner" will be the user of the top-level post for retractions too. Be // aware that another reasonable possibility is that it's the "$owner" of the deleted comment. -// TODO -// CHECK 1. If we receive a retraction from Diaspora to be relayed by us, we need to insert the signature -// into the DB and call notifier.php -// CHECK 2. diaspora_send_retraction() needs to be modified to send -// Diaspora a retraction for it to relay when appropriate -// CHECK 3. notifier.php (and delivery.php?) need to be modified to call the right functions for the right -// retraction situation -// 4. If possible, modify notifier.php (and delivery.php?) to remove the relayable retraction's signature -// from the DB after finishing with relaying retractions - $a = get_app(); @@ -2216,20 +2192,20 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $like = false; $relay_retract = false; $sql_sign_id = 'iid'; - if($item['verb'] === ACTIVITY_LIKE) { + if( $item['deleted']) { + $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); + $relay_retract = true; + $sql_sign_id = 'retract_iid'; + $target_type = ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); + } + elseif($item['verb'] === ACTIVITY_LIKE) { $tpl = get_markup_template('diaspora_like_relay.tpl'); $like = true; $target_type = 'Post'; $positive = (($item['deleted']) ? 'false' : 'true'); } - elseif(! $item['deleted']) { - $tpl = get_markup_template('diaspora_comment_relay.tpl'); - } else { - $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); - $relay_retract = true; - $sql_sign_id = 'retract_iid'; - $target_type = 'Comment'; + $tpl = get_markup_template('diaspora_comment_relay.tpl'); } $body = $item['body']; diff --git a/include/items.php b/include/items.php index 8858ca64fa..897036c26f 100644 --- a/include/items.php +++ b/include/items.php @@ -3281,33 +3281,33 @@ function drop_item($id,$interactive = true) { } // Add a relayable_retraction signature for Diaspora. Note that we can't add a target_author_signature - // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting - // the comment, that means we're the home of the post, and Diaspora will only + // if the comment/like was deleted by a remote user. That should be ok, because if a remote user is deleting + // the comment/like, that means we're the home of the post, and Diaspora will only // check the parent_author_signature of retractions that it doesn't have to relay further - if( strcmp($item['type'], 'activity') != 0) { - $signed_text = $item['guid'] . ';' . 'Comment'; + $signed_text = $item['guid'] . ';' . ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); - if(local_user() == $item['uid']) { + if(local_user() == $item['uid']) { - $handle = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256')); - } - else { - $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", - $item['contact-id'] - ); - if(count($r)) - $handle = $r['nick'] . '@' . substr($r['url'], strpos($r['url'],'://') + 3, strpos($r['url'],'/profile') - 1); - } - - if(isset($handle) - q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - intval($item['id']), - dbesc($signed_text), - dbesc($authorsig), - dbesc($handle) - ); + $handle = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256')); } + else { + $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", + $item['contact-id'] + ); + if(count($r)) { + $handle = $r['nick'] . '@' . substr($r['url'], strpos($r['url'],'://') + 3, strpos($r['url'],'/profile') - 1); + $authorsig = ''; + } + } + + if(isset($handle)) + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($item['id']), + dbesc($signed_text), + dbesc($authorsig), + dbesc($handle) + ); } $drop_id = intval($item['id']); diff --git a/include/notifier.php b/include/notifier.php index 68f230a05f..be50366d5c 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -738,7 +738,7 @@ function notifier_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($top_level || $followup) && ($target_item['verb'] !== ACTIVITY_LIKE)) { + elseif(($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup) && ($target_item['verb'] !== ACTIVITY_LIKE)) { // diaspora delete, including relayable_retractions that need to be relayed diaspora_send_retraction($target_item,$owner,$contact); break; @@ -748,7 +748,7 @@ function notifier_run($argv, $argc){ diaspora_send_followup($target_item,$owner,$contact); break; } - elseif($target_item['parent'] != $target_item['id']) { + elseif($target_item['uri'] !== $target_item['parent-uri']) { // we are the relay - send comments, likes, unlikes and relayable_retractions to our conversants diaspora_send_relay($target_item,$owner,$contact); break; diff --git a/update.php b/update.php index 9d534a127a..b542d75ba5 100644 --- a/update.php +++ b/update.php @@ -1276,7 +1276,7 @@ function update_1146() { /* function update_xxxx() { - $r1 = q("ALTER TABLE `sign` MODIFY `iid` SET DEFAULT '0'"); + $r1 = q("ALTER TABLE `sign` ALTER `iid` SET DEFAULT '0'"); $r2 = q("ALTER TABLE `sign` ADD `retract_iid` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `iid`"); $r3 = q("ALTER TABLE `sign` ADD INDEX ( `retract_iid` )"); if((! $r1) || (! $r2) || (! $r3)) diff --git a/view/diaspora_like_relay.tpl b/view/diaspora_like_relay.tpl old mode 100644 new mode 100755 index 65559b05bf..8b67f4de33 --- a/view/diaspora_like_relay.tpl +++ b/view/diaspora_like_relay.tpl @@ -5,9 +5,9 @@ $target_type $parent_guid $parentsig - $authrosig + $authorsig $positive $handle - \ No newline at end of file + diff --git a/view/diaspora_relayable_retraction.tpl b/view/diaspora_relayable_retraction.tpl old mode 100644 new mode 100755 index 27936f7f3b..73cff8343a --- a/view/diaspora_relayable_retraction.tpl +++ b/view/diaspora_relayable_retraction.tpl @@ -3,7 +3,7 @@ $target_type $guid - $parentauthorsig + $parentsig $authorsig $handle From cde0de965f8f2fde2b289ebcb1c1814ffa303ca6 Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Sat, 2 Jun 2012 23:56:42 -0600 Subject: [PATCH 5/8] first shot at getting like/unlike functions to work consistently --- include/delivery.php | 12 ++--- include/diaspora.php | 22 ++++++--- include/items.php | 8 ++- include/notifier.php | 9 ++-- mod/like.php | 113 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 142 insertions(+), 22 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index 235b766c5f..e6cfc81554 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -509,17 +509,17 @@ function delivery_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($target_item['uri'] === $target_item['parent-uri']) && ($target_item['verb'] !== ACTIVITY_LIKE)) { - logger('delivery: diaspora retract: ' . $loc); - // diaspora delete, + elseif(($target_item['deleted']) && ($target_item['uri'] === $target_item['parent-uri'])) { + // top-level retraction + logger('delivery: diaspora retract: ' . $loc); + diaspora_send_retraction($target_item,$owner,$contact,$public_message); break; } elseif($target_item['uri'] !== $target_item['parent-uri']) { + // we are the relay - send comments, likes and relayable_retractions to our conversants + logger('delivery: diaspora relay: ' . $loc); - logger('delivery: diaspora relay: ' . $loc); - - // we are the relay - send comments, likes, unlikes and relayable_retractions to our conversants diaspora_send_relay($target_item,$owner,$contact,$public_message); break; } diff --git a/include/diaspora.php b/include/diaspora.php index 10c56564b7..3bf4a9cc61 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -2125,7 +2125,8 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { $tpl = get_markup_template('diaspora_like.tpl'); $like = true; $target_type = 'Post'; - $positive = (($item['deleted']) ? 'false' : 'true'); +// $positive = (($item['deleted']) ? 'false' : 'true'); + $positive = 'true'; } else { $tpl = get_markup_template('diaspora_comment.tpl'); @@ -2202,7 +2203,8 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $tpl = get_markup_template('diaspora_like_relay.tpl'); $like = true; $target_type = 'Post'; - $positive = (($item['deleted']) ? 'false' : 'true'); +// $positive = (($item['deleted']) ? 'false' : 'true'); + $positive = 'true'; } else { $tpl = get_markup_template('diaspora_comment_relay.tpl'); @@ -2220,9 +2222,6 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { // owner (parent author) signature // Note that mod/item.php seems to take care of creating a signature for Diaspora for replies // created on our own account - // - // comments from other networks will be relayed under our name, with a brief - // preamble to describe what's happening and noting the real author $r = q("select * from sign where " . $sql_sign_id . " = %d limit 1", intval($item['id']) @@ -2235,6 +2234,12 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { } else { + // Author signature information (for likes, comments, and retractions of likes or comments, + // whether from Diaspora or Friendica) must be placed in the `sign` table before this + // function is called + logger('diaspora_send_relay: original author signature not found, cannot send relayable'); + return; +/* $itemcontact = q("select * from contact where `id` = %d limit 1", intval($item['contact-id']) ); @@ -2273,6 +2278,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { dbesc($handle) ); } +*/ } // sign it with the top-level owner's signature @@ -2306,11 +2312,11 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { $a = get_app(); $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - // Check if the retraction is for a top-level post, or whether it's for a comment - if( $item['id'] !== $item['parent'] ) { + // Check whether the retraction is for a top-level post or whether it's a relayable + if( $item['uri'] !== $item['parent-uri'] ) { $tpl = get_markup_template('diaspora_relay_retraction.tpl'); - $target_type = 'Comment'; + $target_type = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); } else { diff --git a/include/items.php b/include/items.php index 897036c26f..6b16810b22 100644 --- a/include/items.php +++ b/include/items.php @@ -3281,9 +3281,11 @@ function drop_item($id,$interactive = true) { } // Add a relayable_retraction signature for Diaspora. Note that we can't add a target_author_signature - // if the comment/like was deleted by a remote user. That should be ok, because if a remote user is deleting - // the comment/like, that means we're the home of the post, and Diaspora will only + // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting + // the comment, that means we're the home of the post, and Diaspora will only // check the parent_author_signature of retractions that it doesn't have to relay further + // + // I don't think this function gets called for an "unlike," but I'll check anyway $signed_text = $item['guid'] . ';' . ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); if(local_user() == $item['uid']) { @@ -3296,6 +3298,8 @@ function drop_item($id,$interactive = true) { $item['contact-id'] ); if(count($r)) { + // The below handle only works for NETWORK_DFRN. I think that's ok, because this function + // only handles DFRN deletes $handle = $r['nick'] . '@' . substr($r['url'], strpos($r['url'],'://') + 3, strpos($r['url'],'/profile') - 1); $authorsig = ''; } diff --git a/include/notifier.php b/include/notifier.php index be50366d5c..f0a1940d49 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -738,18 +738,19 @@ function notifier_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup) && ($target_item['verb'] !== ACTIVITY_LIKE)) { - // diaspora delete, including relayable_retractions that need to be relayed + elseif(($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) { + // send both top-level retractions and relayable retractions for owner to relay diaspora_send_retraction($target_item,$owner,$contact); break; } elseif($followup) { - // send comments, likes and retractions of likes to owner to relay + // send comments and likes to owner to relay diaspora_send_followup($target_item,$owner,$contact); break; } elseif($target_item['uri'] !== $target_item['parent-uri']) { - // we are the relay - send comments, likes, unlikes and relayable_retractions to our conversants + // we are the relay - send comments, likes and relayable_retractions + // (of comments and likes) to our conversants diaspora_send_relay($target_item,$owner,$contact); break; } diff --git a/mod/like.php b/mod/like.php index 6b97fafb56..06d27659bb 100644 --- a/mod/like.php +++ b/mod/like.php @@ -104,6 +104,7 @@ function like_content(&$a) { return; } + $r = q("SELECT `id` FROM `item` WHERE `verb` = '%s' AND `deleted` = 0 AND `contact-id` = %d AND ( `parent` = '%s' OR `parent-uri` = '%s') LIMIT 1", dbesc($activity), @@ -118,7 +119,58 @@ function like_content(&$a) { intval($r[0]['id']) ); - proc_run('php',"include/notifier.php","like","$post_id"); + // Clean up the `sign` table + $r2 = q("DELETE FROM `sign` WHERE `iid` = %d", + intval($r[0]['id']) + ); + + // Save the author information for the unlike in case we need to relay to Diaspora + // Note that we can only create a signature for a user of the local server. We don't have + // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it + // means we are the relay, and for relayable_retractions, Diaspora + // only checks the parent_author_signature if it doesn't have to relay further + // + // If $item['resource-id'] exists, it means the item is a photo. Diaspora doesn't support + // likes on photos, so don't bother. + + if(($activity === ACTIVITY_LIKE) && (! $item['resource-id'])) { + $signed_text = $r[0]['guid'] . ';' . 'Like'; + + if( contact['network'] === NETWORK_DIASPORA) + $diaspora_handle = $contact['addr']; + else { // Only works for NETWORK_DFRN + $contact_baseurl = substr($contact['url'], strpos($contact['url'],'://') + 3, strpos($contact['url'],'/profile') - 1); + $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl; + + // Get contact's private key if he's a user of the local Friendica server + $r2 = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc(contact['url']) + ); + + if( $r2) { + $contact_uid = $r2['uid']; + $r2 = q("SELECT prvkey FROM user WHERE id = %d LIMIT 1", + intval($contact_uid) + ); + + if( $r2) + $authorsig = base64_encode(rsa_sign($signed_text,$r2['prvkey'],'sha256')); + } + } + + if(! isset($authorsig)) + $authorsig = ''; + + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($r[0]['id']), + dbesc($signed_text), + dbesc($authorsig), + dbesc($diaspora_handle) + ); + } + +// proc_run('php',"include/notifier.php","like","$post_id"); // $post_id isn't defined here! + proc_run('php',"include/notifier.php","like","$r[0]['id']"); return; } @@ -191,6 +243,63 @@ EOT; ); } + + // Save the author information for the like in case we need to relay to Diaspora + // Note that we can only create a signature for a user of the local server. We don't have + // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it + // means we are the relay, and for relayable_retractions, Diaspora + // only checks the parent_author_signature if it doesn't have to relay further + + if(($activity === ACTIVITY_LIKE) && ($post_type === t('status'))) { + if( contact['network'] === NETWORK_DIASPORA) + $diaspora_handle = $contact['addr']; + else { // Only works for NETWORK_DFRN + $contact_baseurl = substr($contact['url'], strpos($contact['url'],'://') + 3, strpos($contact['url'],'/profile') - 1); + $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl; + + // Get contact's private key if he's a user of the local Friendica server + $r2 = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc(contact['url']) + ); + + if( $r2) { + $contact_uid = $r2['uid']; + $r2 = q("SELECT prvkey FROM user WHERE id = %d LIMIT 1", + intval($contact_uid) + ); + + if( $r2) + $contact_uprvkey = $r2['prvkey']; + } + } + + $r = q("SELECT guid, parent FROM `item` WHERE id = %d LIMIT 1", + intval($post_id) + ); + if( $r) { + $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1", + intval($r[0]['parent'), + intval($r[0]['parent') + ); + if( $p) { + $signed_text = $r[0]['guid'] . ';Post;' . $p[0]['guid'] . ';true;' . $diaspora_handle; + + if(isset($contact_uprvkey)) + $authorsig = base64_encode(rsa_sign($signed_text,$contact_uprvkey,'sha256')); + else + $authorsig = ''; + + q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($post_id), + dbesc($signed_text), + dbesc($authorsig), + dbesc($diaspora_handle) + ); + } + } + } + + $arr['id'] = $post_id; call_hooks('post_local_end', $arr); @@ -199,4 +308,4 @@ EOT; killme(); // return; // NOTREACHED -} \ No newline at end of file +} From 06263f72a8d37688f305b563543bca86d939653e Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Sun, 3 Jun 2012 11:12:16 -0600 Subject: [PATCH 6/8] cleanup and logging --- include/diaspora.php | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/include/diaspora.php b/include/diaspora.php index 3bf4a9cc61..1e6662f040 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1605,22 +1605,28 @@ function diaspora_like($importer,$xml,$msg) { logger('diaspora_like: duplicate like: ' . $guid); return; } + // Note: I don't think "Like" objects with positive = "false" are ever actually used + // It looks like "RelayableRetractions" are used for "unlike" instead if($positive === 'false') { - q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", + logger('diaspora_like: received a like with positive set to "false"...ignoring'); +/* q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($r[0]['id']), intval($importer['uid']) - ); + );*/ // FIXME // send notification via proc_run() return; } } + // Note: I don't think "Like" objects with positive = "false" are ever actually used + // It looks like "RelayableRetractions" are used for "unlike" instead if($positive === 'false') { - logger('diaspora_like: unlike received with no corresponding like'); + logger('diaspora_like: received a like with positive set to "false"'); + logger('diaspora_like: unlike received with no corresponding like...ignoring'); return; } - $author_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; + $signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; $author_signature = base64_decode($author_signature); @@ -1638,20 +1644,20 @@ function diaspora_like($importer,$xml,$msg) { } } - if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { + if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { logger('diaspora_like: verification failed.'); return; } if($parent_author_signature) { - $owner_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; + //$owner_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; $parent_author_signature = base64_decode($parent_author_signature); $key = $msg['key']; - if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { logger('diaspora_like: owner verification failed.'); return; } @@ -2127,6 +2133,9 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { $target_type = 'Post'; // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; + + if(($item['deleted'])) + logger('diaspora_send_followup: received deleted "like". Those should go to diaspora_send_retraction'); } else { $tpl = get_markup_template('diaspora_comment.tpl'); @@ -2163,14 +2172,6 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { -// I think the first comment or like on a post whose home is our Friendica server is saved as an item -// as the top-level post owner's contact for writer of the comment or post. Thus, the "uid" -// on the item is `user`.`id` of the top-level post owner. That user is passed to this function -// as "$owner." -// -// I'm assuming for now that "$owner" will be the user of the top-level post for retractions too. Be -// aware that another reasonable possibility is that it's the "$owner" of the deleted comment. - $a = get_app(); @@ -2215,13 +2216,8 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $text = html_entity_decode(bb2diaspora($body)); - // fetch the original signature if somebody sent the post to us to relay - // - // If we are relaying for a reply originating on our own account, there wasn't a 'send to relay' - // action. It wasn't needed. In that case create the original signature and the - // owner (parent author) signature - // Note that mod/item.php seems to take care of creating a signature for Diaspora for replies - // created on our own account + // fetch the original signature if the relayable was created by a Diaspora + // or DFRN user. Relayables for other networks are not supported. $r = q("select * from sign where " . $sql_sign_id . " = %d limit 1", intval($item['id']) @@ -2454,3 +2450,5 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) { return(($return_code) ? $return_code : (-1)); } + + From 9920fb39e566a10c44aa7ead9603ff3d1893a01a Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Sun, 3 Jun 2012 14:32:17 -0600 Subject: [PATCH 7/8] Debugged implementation of Diaspora relayable_retractions Diaspora "relayable_retraction" is now supported by Friendica. The following should now work: Friendica top-level post: Diaspora comment deleted, disappears in Friendica Friendica comment deleted, disappears in Diaspora Diaspora like retracted, disappears in Friendica Friendica like retracted, disappears in Diaspora Diaspora top-level post: Same There are still exceptions, however. First, Friendica and Diaspora seem to frequently reject comments with an "invalid signature" error. This can probably be fixed. Also, some comments/likes/retractions seem to just disappear on the Diaspora side. In the Diaspora log these seem to be accompanied by a "not a valid object" error, often preceeded by a "received a comment but no corresponding post" error. These seem to be purely internal, since sometimes it works for some Diaspora contacts but not others. --- include/diaspora.php | 0 include/items.php | 4 ++- mod/like.php | 62 +++++++++++++++++++++++++------------------- 3 files changed, 38 insertions(+), 28 deletions(-) mode change 100644 => 100755 include/diaspora.php mode change 100644 => 100755 include/items.php mode change 100644 => 100755 mod/like.php diff --git a/include/diaspora.php b/include/diaspora.php old mode 100644 new mode 100755 diff --git a/include/items.php b/include/items.php old mode 100644 new mode 100755 index 6b16810b22..4513db1dbb --- a/include/items.php +++ b/include/items.php @@ -3300,7 +3300,9 @@ function drop_item($id,$interactive = true) { if(count($r)) { // The below handle only works for NETWORK_DFRN. I think that's ok, because this function // only handles DFRN deletes - $handle = $r['nick'] . '@' . substr($r['url'], strpos($r['url'],'://') + 3, strpos($r['url'],'/profile') - 1); + $handle_baseurl_start = strpos($r['url'],'://') + 3; + $handle_baseurl_length = strpos($r['url'],'/profile') - $handle_baseurl_start; + $handle = $r['nick'] . '@' . substr($r['url'], $handle_baseurl_start, $handle_baseurl_length); $authorsig = ''; } } diff --git a/mod/like.php b/mod/like.php old mode 100644 new mode 100755 index 06d27659bb..942a04fe7f --- a/mod/like.php +++ b/mod/like.php @@ -105,7 +105,7 @@ function like_content(&$a) { } - $r = q("SELECT `id` FROM `item` WHERE `verb` = '%s' AND `deleted` = 0 + $r = q("SELECT * FROM `item` WHERE `verb` = '%s' AND `deleted` = 0 AND `contact-id` = %d AND ( `parent` = '%s' OR `parent-uri` = '%s') LIMIT 1", dbesc($activity), intval($contact['id']), @@ -113,15 +113,17 @@ function like_content(&$a) { dbesc($item_id) ); if(count($r)) { + $like_item = $r[0]; + // Already voted, undo it $r = q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), - intval($r[0]['id']) + intval($like_item['id']) ); // Clean up the `sign` table - $r2 = q("DELETE FROM `sign` WHERE `iid` = %d", - intval($r[0]['id']) + $r = q("DELETE FROM `sign` WHERE `iid` = %d", + intval($like_item['id']) ); // Save the author information for the unlike in case we need to relay to Diaspora @@ -134,27 +136,29 @@ function like_content(&$a) { // likes on photos, so don't bother. if(($activity === ACTIVITY_LIKE) && (! $item['resource-id'])) { - $signed_text = $r[0]['guid'] . ';' . 'Like'; + $signed_text = $like_item['guid'] . ';' . 'Like'; - if( contact['network'] === NETWORK_DIASPORA) + if( $contact['network'] === NETWORK_DIASPORA) $diaspora_handle = $contact['addr']; else { // Only works for NETWORK_DFRN - $contact_baseurl = substr($contact['url'], strpos($contact['url'],'://') + 3, strpos($contact['url'],'/profile') - 1); + $contact_baseurl_start = strpos($contact['url'],'://') + 3; + $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start; + $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length); $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl; // Get contact's private key if he's a user of the local Friendica server - $r2 = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", - dbesc(contact['url']) + $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc($contact['url']) ); - if( $r2) { - $contact_uid = $r2['uid']; - $r2 = q("SELECT prvkey FROM user WHERE id = %d LIMIT 1", + if( $r) { + $contact_uid = $r['uid']; + $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1", intval($contact_uid) ); - if( $r2) - $authorsig = base64_encode(rsa_sign($signed_text,$r2['prvkey'],'sha256')); + if( $r) + $authorsig = base64_encode(rsa_sign($signed_text,$r['prvkey'],'sha256')); } } @@ -162,15 +166,17 @@ function like_content(&$a) { $authorsig = ''; q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - intval($r[0]['id']), + intval($like_item['id']), dbesc($signed_text), dbesc($authorsig), dbesc($diaspora_handle) ); } + // proc_run('php',"include/notifier.php","like","$post_id"); // $post_id isn't defined here! - proc_run('php',"include/notifier.php","like","$r[0]['id']"); + $like_item_id = $like_item['id']; + proc_run('php',"include/notifier.php","like","$like_item_id"); return; } @@ -251,25 +257,27 @@ EOT; // only checks the parent_author_signature if it doesn't have to relay further if(($activity === ACTIVITY_LIKE) && ($post_type === t('status'))) { - if( contact['network'] === NETWORK_DIASPORA) + if( $contact['network'] === NETWORK_DIASPORA) $diaspora_handle = $contact['addr']; else { // Only works for NETWORK_DFRN - $contact_baseurl = substr($contact['url'], strpos($contact['url'],'://') + 3, strpos($contact['url'],'/profile') - 1); + $contact_baseurl_start = strpos($contact['url'],'://') + 3; + $contact_baseurl_length = strpos($contact['url'],'/profile') - $contact_baseurl_start; + $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length); $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl; // Get contact's private key if he's a user of the local Friendica server - $r2 = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", - dbesc(contact['url']) + $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc($contact['url']) ); - if( $r2) { - $contact_uid = $r2['uid']; - $r2 = q("SELECT prvkey FROM user WHERE id = %d LIMIT 1", + if( $r) { + $contact_uid = $r['uid']; + $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1", intval($contact_uid) ); - if( $r2) - $contact_uprvkey = $r2['prvkey']; + if( $r) + $contact_uprvkey = $r['prvkey']; } } @@ -278,8 +286,8 @@ EOT; ); if( $r) { $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1", - intval($r[0]['parent'), - intval($r[0]['parent') + intval($r[0]['parent']), + intval($r[0]['parent']) ); if( $p) { $signed_text = $r[0]['guid'] . ';Post;' . $p[0]['guid'] . ';true;' . $diaspora_handle; From 2a01ae8149e8a16ea0c0c5619a8dd0b682dba21c Mon Sep 17 00:00:00 2001 From: Zach Prezkuta Date: Sun, 3 Jun 2012 14:52:42 -0600 Subject: [PATCH 8/8] database updates --- boot.php | 2 +- database.sql | 6 ++++-- update.php | 7 ++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/boot.php b/boot.php index 559cd8c327..742948f7bf 100644 --- a/boot.php +++ b/boot.php @@ -11,7 +11,7 @@ require_once('include/cache.php'); define ( 'FRIENDICA_PLATFORM', 'Friendica'); define ( 'FRIENDICA_VERSION', '3.0.1362' ); define ( 'DFRN_PROTOCOL_VERSION', '2.23' ); -define ( 'DB_UPDATE_VERSION', 1147 ); +define ( 'DB_UPDATE_VERSION', 1148 ); define ( 'EOL', "
\r\n" ); define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); diff --git a/database.sql b/database.sql index b20846bad5..c1d1b27e4e 100644 --- a/database.sql +++ b/database.sql @@ -944,12 +944,14 @@ CREATE TABLE IF NOT EXISTS `session` ( CREATE TABLE IF NOT EXISTS `sign` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `iid` int(10) unsigned NOT NULL, + `iid` int(10) unsigned NOT NULL DEFAULT '0', + `retract_iid` int(10) unsigned NOT NULL DEFAULT '0', `signed_text` mediumtext NOT NULL, `signature` text NOT NULL, `signer` char(255) NOT NULL, PRIMARY KEY (`id`), - KEY `iid` (`iid`) + KEY `iid` (`iid`), + KEY `retract_iid` (`retract_iid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -------------------------------------------------------- diff --git a/update.php b/update.php index b542d75ba5..35a6771b00 100644 --- a/update.php +++ b/update.php @@ -1,6 +1,6 @@ dumpfile.sql