X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=inline;f=include%2Fdiaspora.php;h=0ca9163a8565cdd8f7f62c08bd84a10e0cb0fd3c;hb=788a6626ef4bd9607f33bbffd0eea0c05a4578c0;hp=10c56564b734998372f04f14143ae2be0aa4471d;hpb=77962aa79df5671e206635cc6980e4b1ac969bf9;p=friendica.git diff --git a/include/diaspora.php b/include/diaspora.php old mode 100644 new mode 100755 index 10c56564b7..0ca9163a85 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1060,45 +1060,64 @@ function diaspora_comment($importer,$xml,$msg) { } $parent_item = $r[0]; - $author_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle; - $author_signature = base64_decode($author_signature); + /* How Diaspora performs comment signature checking: - 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_comment: unable to find author details'); - return; - } - } + - If an item has been sent by the comment author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner should check + the author_signature, then create a parent_author_signature before relaying the comment on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the salmon + */ - if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { - logger('diaspora_comment: verification failed.'); - return; - } + $signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle; + $key = $msg['key']; if($parent_author_signature) { - $owner_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle; + // If a parent_author_signature exists, then we've received the comment + // relayed from the top-level post owner. There's no need to check the + // author_signature if the parent_author_signature is valid $parent_author_signature = base64_decode($parent_author_signature); - $key = $msg['key']; + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_comment: top-level owner verification failed.'); + return; + } + } + else { + // If there's no parent_author_signature, then we've received the comment + // from the comment creator. In that case, the person is commenting on + // our post, so he/she must be a contact of ours and his/her public key + // should be in $msg['key'] + + $author_signature = base64_decode($author_signature); - if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { - logger('diaspora_comment: owner verification failed.'); + if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { + logger('diaspora_comment: comment author verification failed.'); return; } } // Phew! Everything checks out. Now create an item. + // Find the original comment author information. + // We need this to make sure we display the comment author + // information (name and avatar) correctly. + if(strcasecmp($diaspora_handle,$msg['author']) == 0) + $person = $contact; + else { + $person = find_diaspora_person_by_handle($diaspora_handle); + + if(! is_array($person)) { + logger('diaspora_comment: unable to find author details'); + return; + } + } + $body = diaspora2bb($text); $message_id = $diaspora_handle . ':' . $guid; @@ -1605,60 +1624,85 @@ 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 + );*/ + // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes // 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; - $author_signature = base64_decode($author_signature); + /* How Diaspora performs "like" signature checking: - 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_like: unable to find author details'); - return; - } - } + - If an item has been sent by the like author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner should check + the author_signature, then create a parent_author_signature before relaying the like on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the salmon + */ - if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { - logger('diaspora_like: verification failed.'); - return; - } + $signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; + $key = $msg['key']; if($parent_author_signature) { - - $owner_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle; + // If a parent_author_signature exists, then we've received the like + // relayed from the top-level post owner. There's no need to check the + // author_signature if the parent_author_signature is valid $parent_author_signature = base64_decode($parent_author_signature); - $key = $msg['key']; + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_like: top-level owner verification failed.'); + return; + } + } + else { + // If there's no parent_author_signature, then we've received the like + // from the like creator. In that case, the person is "like"ing + // our post, so he/she must be a contact of ours and his/her public key + // should be in $msg['key'] + + $author_signature = base64_decode($author_signature); - if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { - logger('diaspora_like: owner verification failed.'); + if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { + logger('diaspora_like: like creator verification failed.'); return; } } // Phew! Everything checks out. Now create an item. + // Find the original comment author information. + // We need this to make sure we display the comment author + // information (name and avatar) correctly. + if(strcasecmp($diaspora_handle,$msg['author']) == 0) + $person = $contact; + else { + $person = find_diaspora_person_by_handle($diaspora_handle); + + if(! is_array($person)) { + logger('diaspora_like: unable to find author details'); + return; + } + } + $uri = $diaspora_handle . ':' . $guid; $activity = ACTIVITY_LIKE; @@ -1796,39 +1840,38 @@ function diaspora_signed_retraction($importer,$xml,$msg) { $signed_data = $guid . ';' . $type ; + $key = $msg['key']; - $sig_decode = base64_decode($sig); + /* How Diaspora performs relayable_retraction signature checking: - if(strcasecmp($diaspora_handle,$msg['author']) == 0) { - $person = $contact; - $key = $msg['key']; - } - else { - $person = find_diaspora_person_by_handle($diaspora_handle); + - If an item has been sent by the item author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner checks + the author_signature, then creates a parent_author_signature before relaying the item on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the salmon + */ - if(is_array($person) && x($person,'pubkey')) - $key = $person['pubkey']; - else { - logger('diaspora_signed_retraction: unable to find author details'); + if($parent_author_signature) { + + $parent_author_signature = base64_decode($parent_author_signature); + + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_signed_retraction: top-level post owner verification failed'); return; } - } - if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) { - logger('diaspora_signed_retraction: retraction-owner verification failed.' . print_r($msg,true)); - return; } + else { - if($parent_author_signature) { - $parent_author_signature = base64_decode($parent_author_signature); - - $key = $msg['key']; + $sig_decode = base64_decode($sig); - 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'); + 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' || $type === 'Comment' || $type === 'Like') { @@ -2107,7 +2150,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { $a = get_app(); $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $theiraddr = $contact['addr']; +// $theiraddr = $contact['addr']; // 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. @@ -2125,7 +2168,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'); @@ -2162,19 +2209,14 @@ 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(); $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $theiraddr = $contact['addr']; +// $theiraddr = $contact['addr']; + + $body = $item['body']; + $text = html_entity_decode(bb2diaspora($body)); // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always @@ -2193,36 +2235,33 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = 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'); + $sender_signed_text = $item['guid'] . ';' . $target_type ; + + $sql_sign_id = 'retract_iid'; + $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); } 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'; + $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $myaddr; + + $tpl = get_markup_template('diaspora_like_relay.tpl'); } - else { + else { // item is a comment + $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr; + $tpl = get_markup_template('diaspora_comment_relay.tpl'); } - $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 + // 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']) @@ -2235,49 +2274,25 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { } else { - $itemcontact = q("select * from contact where `id` = %d limit 1", - intval($item['contact-id']) - ); - if(count($itemcontact)) { - if(! $itemcontact[0]['self']) { - $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 . ';' . $handle; - elseif($relay_retract) - $signed_text = $item['guid'] . ';' . $target_type; - else - $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle; - - $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')); - - q("insert into sign (`" . $sql_sign_id . "`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - intval($item['id']), - dbesc($signed_text), - dbesc($authorsig), - dbesc($handle) - ); - } + // 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; } - // sign it with the top-level owner's signature + // Sign the relayable with the top-level owner's signature + // + // We'll use the $sender_signed_text that we just created, instead of the $signed_text + // stored in the database, because that provides the best chance that Diaspora will + // be able to reconstruct the signed text the same way we did. This is particularly a + // concern for the comment, whose signed text includes the text of the comment. The + // smallest change in the text of the comment, including removing whitespace, will + // make the signature verification fail. Since we translate from BB code to Diaspora's + // markup at the top of this function, which is AFTER we placed the original $signed_text + // in the database, it's hazardous to trust the original $signed_text. - $parentauthorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')); + $parentauthorsig = base64_encode(rsa_sign($sender_signed_text,$owner['uprvkey'],'sha256')); $msg = replace_macros($tpl,array( '$guid' => xmlify($item['guid']), @@ -2306,11 +2321,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 { @@ -2448,3 +2463,5 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) { return(($return_code) ? $return_code : (-1)); } + +