function p_init($a) { if ($a->argc != 2) { header($_SERVER["SERVER_PROTOCOL"] . ' 510 ' . t('Not Extended')); killme(); } $guid = $a->argv[1]; if (strtolower(substr($guid, -4)) != ".xml") { header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); killme(); } $guid = strtolower(substr($guid, 0, -4)); $item = q("SELECT `body`, `guid`, `contact-id`, `private`, `created`, `app` FROM `item` WHERE `uid` = 0 AND `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1", dbesc($guid), NETWORK_DFRN, NETWORK_DIASPORA); if (!$item) { header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); killme(); } $post = array(); $reshared = diaspora_is_reshare($item[0]["body"]); if ($reshared) { $nodename = "reshare"; $post["root_diaspora_id"] = $reshared["root_handle"]; $post["root_guid"] = $reshared["root_guid"]; $post["guid"] = $item[0]["guid"]; $post["diaspora_handle"] = diaspora_handle_from_contact($item[0]["contact-id"]); $post["public"] = !$item[0]["private"] ? 'true' : 'false'; $post["created_at"] = datetime_convert('UTC', 'UTC', $item[0]["created"]); } else { $nodename = "status_message"; $post["raw_message"] = str_replace("&", "&", bb2diaspora($item[0]["body"])); $post["guid"] = $item[0]["guid"]; $post["diaspora_handle"] = diaspora_handle_from_contact($item[0]["contact-id"]); $post["public"] = !$item[0]["private"] ? 'true' : 'false'; $post["created_at"] = datetime_convert('UTC', 'UTC', $item[0]["created"]); $post["provider_display_name"] = $item[0]["app"]; } $dom = new DOMDocument("1.0"); $root = $dom->createElement("XML"); $dom->appendChild($root); $postelement = $dom->createElement("post"); $root->appendChild($postelement); $statuselement = $dom->createElement($nodename); $postelement->appendChild($statuselement); foreach ($post as $index => $value) { $postnode = $dom->createElement($index, $value); $statuselement->appendChild($postnode); } header("Content-Type: application/xml; charset=utf-8"); $xml = $dom->saveXML(); // Diaspora doesn't send the XML header, so we remove them as well. // So we avoid possible compatibility problems. if (substr($xml, 0, 21) == '<?xml version="1.0"?>') { $xml = trim(substr($xml, 21)); } echo $xml; killme(); }
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); // $theiraddr = $contact['addr']; $body = $item['body']; $text = html_entity_decode(bb2diaspora($body)); // Diaspora doesn't support threaded comments, but some // versions of Diaspora (i.e. Diaspora-pistos) support // likes on comments if ($item['verb'] === ACTIVITY_LIKE && $item['thr-parent']) { $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1", dbesc($item['thr-parent'])); } else { // 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 guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1", intval($item['parent']), intval($item['parent'])); } if (count($p)) { $parent = $p[0]; } else { return; } $like = false; $relay_retract = false; $sql_sign_id = 'iid'; if ($item['deleted']) { $relay_retract = true; $target_type = $item['verb'] === ACTIVITY_LIKE ? 'Like' : 'Comment'; $sql_sign_id = 'retract_iid'; $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); } elseif ($item['verb'] === ACTIVITY_LIKE) { $like = true; $target_type = $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment'; // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; $tpl = get_markup_template('diaspora_like_relay.tpl'); } else { // item is a comment $tpl = get_markup_template('diaspora_comment_relay.tpl'); } // 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)) { $orig_sign = $r[0]; $signed_text = $orig_sign['signed_text']; $authorsig = $orig_sign['signature']; $handle = $orig_sign['signer']; } 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; }*/ /* Since the author signature is only checked by the parent, not by the relay recipients, * I think it may not be necessary for us to do so much work to preserve all the original * signatures. The important thing that Diaspora DOES need is the original creator's handle. * Let's just generate that and forget about all the original author signature stuff. * * Note: this might be more of an problem if we want to support likes on comments for older * versions of Diaspora (diaspora-pistos), but since there are a number of problems with * doing that, let's ignore it for now. * * Currently, only DFRN contacts are supported. StatusNet shouldn't be hard, but it hasn't * been done yet */ $handle = diaspora_handle_from_contact($item['contact-id']); if (!$handle) { return; } if ($relay_retract) { $sender_signed_text = $item['guid'] . ';' . $target_type; } elseif ($like) { $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle; } else { $sender_signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle; } // 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($sender_signed_text, $owner['uprvkey'], 'sha256')); $msg = replace_macros($tpl, array('$guid' => xmlify($item['guid']), '$parent_guid' => xmlify($parent['guid']), '$target_type' => xmlify($target_type), '$authorsig' => xmlify($authorsig), '$parentsig' => xmlify($parentauthorsig), '$body' => xmlify($text), '$positive' => xmlify($positive), '$handle' => xmlify($handle))); 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))); //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); return diaspora_transmit($owner, $contact, $slap, $public_batch); }
function diaspora_send_relay($item, $owner, $contact, $public_batch = false) { $a = get_app(); $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3); $text = bb2diaspora_itembody($item); $body = $text; // Diaspora doesn't support threaded comments, but some // versions of Diaspora (i.e. Diaspora-pistos) support // likes on comments if ($item['verb'] === ACTIVITY_LIKE && $item['thr_parent']) { $p = q("select * from item where mid = '%s' limit 1", dbesc($item['thr_parent'])); } else { // 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 * from item where parent = %d and id = %d limit 1", intval($item['parent']), intval($item['parent'])); } if ($p) { $parent = $p[0]; } else { logger('diaspora_send_relay: no parent'); return; } $like = false; $relay_retract = false; $sql_sign_id = 'iid'; if ($item['item_restrict'] & ITEM_DELETED) { $relay_retract = true; $target_type = $item['verb'] === ACTIVITY_LIKE ? 'Like' : 'Comment'; $sql_sign_id = 'retract_iid'; $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); } elseif ($item['verb'] === ACTIVITY_LIKE) { $like = true; $target_type = $parent['mid'] === $parent['parent_mid'] ? 'Post' : 'Comment'; // $positive = (($item['item_restrict'] & ITEM_DELETED) ? 'false' : 'true'); $positive = 'true'; $tpl = get_markup_template('diaspora_like_relay.tpl'); } else { // item is a comment $tpl = get_markup_template('diaspora_comment_relay.tpl'); } $diaspora_meta = $item['diaspora_meta'] ? json_decode($item['diaspora_meta'], true) : ''; if ($diaspora_meta) { $sender_signed_text = $diaspora_meta['signed_text']; $authorsig = $diaspora_meta['signature']; $handle = $diaspora_meta['signer']; $text = $diaspora_meta['body']; } else { logger('diaspora_send_relay: original author signature not found'); } /* Since the author signature is only checked by the parent, not by the relay recipients, * I think it may not be necessary for us to do so much work to preserve all the original * signatures. The important thing that Diaspora DOES need is the original creator's handle. * Let's just generate that and forget about all the original author signature stuff. * * Note: this might be more of an problem if we want to support likes on comments for older * versions of Diaspora (diaspora-pistos), but since there are a number of problems with * doing that, let's ignore it for now. * * */ // bug - nomadic identity may/will affect diaspora_handle_from_contact if (!$handle) { if ($item['author_xchan'] === $owner['channel_hash']) { $handle = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3); } else { $handle = diaspora_handle_from_contact($item['author_xchan']); } } if (!$handle) { logger('diaspora_send_relay: no handle'); return; } if (!$sender_signed_text) { if ($relay_retract) { $sender_signed_text = $item['mid'] . ';' . $target_type; } elseif ($like) { $sender_signed_text = $positive . ';' . $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $handle; } else { $sender_signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $handle; } } // 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($sender_signed_text, $owner['channel_prvkey'], 'sha256')); $msg = replace_macros($tpl, array('$guid' => xmlify($item['mid']), '$parent_guid' => xmlify($parent['mid']), '$target_type' => xmlify($target_type), '$authorsig' => xmlify($authorsig), '$parentsig' => xmlify($parentauthorsig), '$body' => xmlify($text), '$positive' => xmlify($positive), '$handle' => xmlify($handle))); logger('diaspora_send_relay: base message: ' . $msg, LOGGER_DATA); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg, $owner, $contact, $owner['channel_prvkey'], $contact['xchan_pubkey'], $public_batch))); return diaspora_transmit($owner, $contact, $slap, $public_batch); }
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); // $theiraddr = $contact['addr']; // Diaspora doesn't support threaded comments, but some // versions of Diaspora (i.e. Diaspora-pistos) support // likes on comments if ($item['verb'] === ACTIVITY_LIKE && $item['thr-parent']) { $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1", dbesc($item['thr-parent'])); } else { // 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 guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1", intval($item['parent']), intval($item['parent'])); } if (count($p)) { $parent = $p[0]; } else { return; } $like = false; $relay_retract = false; $sql_sign_id = 'iid'; if ($item['deleted']) { $relay_retract = true; $target_type = $item['verb'] === ACTIVITY_LIKE ? 'Like' : 'Comment'; $sql_sign_id = 'retract_iid'; $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); } elseif ($item['verb'] === ACTIVITY_LIKE) { $like = true; $target_type = $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment'; // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; $tpl = get_markup_template('diaspora_like_relay.tpl'); } else { // item is a comment $tpl = get_markup_template('diaspora_comment_relay.tpl'); } // 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 `signed_text`, `signature`, `signer` FROM `sign` WHERE " . $sql_sign_id . " = %d LIMIT 1", intval($item['id'])); if (count($r)) { $orig_sign = $r[0]; $signed_text = $orig_sign['signed_text']; $authorsig = $orig_sign['signature']; $handle = $orig_sign['signer']; // Friendica servers lower than 3.5 had double encoded the signature ... if (substr($authorsig, -1, 1) != "=") { $authorsig = base64_decode($authorsig); } // Split the signed text $signed_parts = explode(";", $signed_text); // Remove the parent guid array_shift($signed_parts); // Remove the comment guid array_shift($signed_parts); // Remove the handle array_pop($signed_parts); // Glue the parts together $text = implode(";", $signed_parts); } else { // This part is meant for cases where we don't have the signatur. (Which shouldn't happen with posts from Diaspora and Friendica) // This means that the comment won't be accepted by newer Diaspora servers $body = $item['body']; $text = html_entity_decode(bb2diaspora($body)); $handle = diaspora_handle_from_contact($item['contact-id']); if (!$handle) { return; } if ($relay_retract) { $signed_text = $item['guid'] . ';' . $target_type; } elseif ($like) { $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle; } else { $signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle; } $authorsig = base64_encode(rsa_sign($signed_text, $owner['uprvkey'], 'sha256')); } // Sign the relayable with the top-level owner's signature $parentauthorsig = base64_encode(rsa_sign($signed_text, $owner['uprvkey'], 'sha256')); $msg = replace_macros($tpl, array('$guid' => xmlify($item['guid']), '$parent_guid' => xmlify($parent['guid']), '$target_type' => xmlify($target_type), '$authorsig' => xmlify($authorsig), '$parentsig' => xmlify($parentauthorsig), '$body' => xmlify($text), '$positive' => xmlify($positive), '$handle' => xmlify($handle))); 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))); //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); return diaspora_transmit($owner, $contact, $slap, $public_batch); }