diff options
author | friendica <info@friendica.com> | 2012-06-03 14:47:04 -0700 |
---|---|---|
committer | friendica <info@friendica.com> | 2012-06-03 14:47:04 -0700 |
commit | a66baf29188248fd83ccdf7053a0cf589a9fa8af (patch) | |
tree | 3ec279fab94641faa31d9a031dab93260bc416f3 | |
parent | 959b264c440e0c39ec235defdec42cb485069f18 (diff) | |
parent | 2a01ae8149e8a16ea0c0c5619a8dd0b682dba21c (diff) | |
download | volse-hubzilla-a66baf29188248fd83ccdf7053a0cf589a9fa8af.tar.gz volse-hubzilla-a66baf29188248fd83ccdf7053a0cf589a9fa8af.tar.bz2 volse-hubzilla-a66baf29188248fd83ccdf7053a0cf589a9fa8af.zip |
Merge pull request #323 from fermionic/add-relayable-retraction-support-for-diaspora
Add relayable retraction support for diaspora
-rw-r--r-- | boot.php | 2 | ||||
-rw-r--r-- | database.sql | 6 | ||||
-rw-r--r-- | include/delivery.php | 15 | ||||
-rwxr-xr-x[-rw-r--r--] | include/diaspora.php | 193 | ||||
-rwxr-xr-x[-rw-r--r--] | include/items.php | 37 | ||||
-rw-r--r-- | include/notifier.php | 21 | ||||
-rw-r--r-- | mod/item.php | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | mod/like.php | 125 | ||||
-rw-r--r-- | update.php | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | view/diaspora_like_relay.tpl | 4 | ||||
-rw-r--r-- | view/diaspora_relay_retraction.tpl | 10 | ||||
-rwxr-xr-x | view/diaspora_relayable_retraction.tpl | 11 |
12 files changed, 371 insertions, 77 deletions
@@ -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', "<br />\r\n" ); define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); diff --git a/database.sql b/database.sql index b20846bad..c1d1b27e4 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/include/delivery.php b/include/delivery.php index 32943d5da..e6cfc8155 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; @@ -508,17 +509,17 @@ function delivery_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($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['parent'] != $target_item['id']) { - - logger('delivery: diaspora relay: ' . $loc); + 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); - // we are the relay - send comments, likes and unlikes to our conversants diaspora_send_relay($target_item,$owner,$contact,$public_message); break; } diff --git a/include/diaspora.php b/include/diaspora.php index f7c2c5e8e..1e6662f04 100644..100755 --- 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", @@ -1602,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); @@ -1635,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; } @@ -1783,38 +1792,89 @@ 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); + $sig_decode = 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)); + if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) { + logger('diaspora_signed_retraction: retraction-owner verification failed.' . print_r($msg,true)); return; } - if($type === 'StatusMessage') { + if($parent_author_signature) { + $parent_author_signature = base64_decode($parent_author_signature); + + $key = $msg['key']; + + 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' || $type === 'Like') { $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", dbesc($guid), intval($importer['uid']) ); 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()), 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']); + } + } } } } @@ -2071,7 +2131,11 @@ 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'; + + 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'); @@ -2111,7 +2175,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $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']; @@ -2127,29 +2191,35 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { else return; - if($item['verb'] === ACTIVITY_LIKE) { + $like = false; + $relay_retract = false; + $sql_sign_id = 'iid'; + 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'); +// $positive = (($item['deleted']) ? 'false' : 'true'); + $positive = 'true'; } else { $tpl = get_markup_template('diaspora_comment_relay.tpl'); - $like = false; } $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 - // 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", + // 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']) ); if(count($r)) { @@ -2160,6 +2230,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']) ); @@ -2168,29 +2244,40 @@ 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')); @@ -2198,14 +2285,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))); @@ -2220,14 +2308,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 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 = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : '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))); @@ -2351,3 +2450,5 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) { return(($return_code) ? $return_code : (-1)); } + + diff --git a/include/items.php b/include/items.php index 0ed16217f..4513db1db 100644..100755 --- a/include/items.php +++ b/include/items.php @@ -3278,7 +3278,42 @@ 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 + // + // 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']) { + + $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)) { + // The below handle only works for NETWORK_DFRN. I think that's ok, because this function + // only handles DFRN deletes + $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 = ''; + } + } + + 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 070e7a436..f0a1940d4 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; @@ -596,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')) @@ -737,18 +738,19 @@ function notifier_run($argv, $argc){ // unsupported break; } - elseif(($target_item['deleted']) && ($target_item['verb'] !== ACTIVITY_LIKE)) { - // diaspora delete, + 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['parent'] != $target_item['id']) { - // we are the relay - send comments, likes and unlikes to our conversants + elseif($target_item['uri'] !== $target_item['parent-uri']) { + // 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; } @@ -858,6 +860,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 497cf5daa..c1c0b14ec 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/mod/like.php b/mod/like.php index 6b97fafb5..942a04fe7 100644..100755 --- a/mod/like.php +++ b/mod/like.php @@ -104,7 +104,8 @@ function like_content(&$a) { return; } - $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']), @@ -112,13 +113,70 @@ 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']) ); - proc_run('php',"include/notifier.php","like","$post_id"); + // Clean up the `sign` table + $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 + // 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 = $like_item['guid'] . ';' . 'Like'; + + if( $contact['network'] === NETWORK_DIASPORA) + $diaspora_handle = $contact['addr']; + else { // Only works for NETWORK_DFRN + $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 + $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc($contact['url']) + ); + + if( $r) { + $contact_uid = $r['uid']; + $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1", + intval($contact_uid) + ); + + if( $r) + $authorsig = base64_encode(rsa_sign($signed_text,$r['prvkey'],'sha256')); + } + } + + if(! isset($authorsig)) + $authorsig = ''; + + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + 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! + $like_item_id = $like_item['id']; + proc_run('php',"include/notifier.php","like","$like_item_id"); return; } @@ -191,6 +249,65 @@ 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_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 + $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", + dbesc($contact['url']) + ); + + if( $r) { + $contact_uid = $r['uid']; + $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1", + intval($contact_uid) + ); + + if( $r) + $contact_uprvkey = $r['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 +316,4 @@ EOT; killme(); // return; // NOTREACHED -}
\ No newline at end of file +} diff --git a/update.php b/update.php index 1b2098e6e..35a6771b0 100644 --- a/update.php +++ b/update.php @@ -1,6 +1,6 @@ <?php -define( 'UPDATE_VERSION' , 1147 ); +define( 'UPDATE_VERSION' , 1148 ); /** * @@ -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,12 @@ function update_1146() { return UPDATE_SUCCESS ; } +function update_1147() { + $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)) + return UPDATE_FAILED ; + return UPDATE_SUCCESS ; +} diff --git a/view/diaspora_like_relay.tpl b/view/diaspora_like_relay.tpl index 65559b05b..8b67f4de3 100644..100755 --- a/view/diaspora_like_relay.tpl +++ b/view/diaspora_like_relay.tpl @@ -5,9 +5,9 @@ <target_type>$target_type</target_type> <parent_guid>$parent_guid</parent_guid> <parent_author_signature>$parentsig</parent_author_signature> - <author_signature>$authrosig</author_signature> + <author_signature>$authorsig</author_signature> <positive>$positive</positive> <diaspora_handle>$handle</diaspora_handle> </like> </post> -</XML>
\ No newline at end of file +</XML> diff --git a/view/diaspora_relay_retraction.tpl b/view/diaspora_relay_retraction.tpl new file mode 100644 index 000000000..e76c7c6c5 --- /dev/null +++ b/view/diaspora_relay_retraction.tpl @@ -0,0 +1,10 @@ +<XML> + <post> + <relayable_retraction> + <target_type>$type</target_type> + <target_guid>$guid</target_guid> + <target_author_signature>$signature</target_author_signature> + <sender_handle>$handle</sender_handle> + </relayable_retraction> + </post> +</XML> diff --git a/view/diaspora_relayable_retraction.tpl b/view/diaspora_relayable_retraction.tpl new file mode 100755 index 000000000..73cff8343 --- /dev/null +++ b/view/diaspora_relayable_retraction.tpl @@ -0,0 +1,11 @@ +<XML> + <post> + <relayable_retraction> + <target_type>$target_type</target_type> + <target_guid>$guid</target_guid> + <parent_author_signature>$parentsig</parent_author_signature> + <target_author_signature>$authorsig</target_author_signature> + <sender_handle>$handle</sender_handle> + </relayable_retraction> + </post> +</XML> |