Beispiel #1
0
function p_init(&$a)
{
    if (argc() < 2) {
        http_status_exit(401);
    }
    $mid = str_replace('.xml', '', argv(1));
    $r = q("select * from item where mid = '%s' and item_wall = 1 and item_private = 0 limit 1", dbesc($mid));
    if (!$r || !perm_is_allowed($r[0]['uid'], '', 'view_stream')) {
        http_status_exit(404);
    }
    $c = q("select * from channel where channel_id = %d limit 1", intval($r[0]['uid']));
    if (!$c) {
        http_status_exit(404);
    }
    $myaddr = $c[0]['channel_address'] . '@' . App::get_hostname();
    $item = $r[0];
    $title = $item['title'];
    $body = bb2diaspora_itembody($item);
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    $tpl = get_markup_template('diaspora_post.tpl', 'addon/diaspora');
    $msg = replace_macros($tpl, array('$body' => xmlify($body), '$guid' => $item['mid'], '$handle' => xmlify($myaddr), '$public' => 'true', '$created' => $created, '$provider' => $item['app'] ? $item['app'] : t('$projectname')));
    header('Content-type: text/xml');
    echo $msg;
    killme();
}
Beispiel #2
0
function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false)
{
    // We won't be able to sign Diaspora comments for authenticated visitors
    // - we don't have their private key
    // since Diaspora doesn't handle edits we can only do this for the original text and not update it.
    require_once 'include/bb2diaspora.php';
    $signed_body = bb2diaspora_itembody($datarray, $walltowall);
    if ($walltowall) {
        logger('wall to wall comment', LOGGER_DEBUG);
        // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
        $signed_body = "\n\n" . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" . $signed_body;
    }
    logger('storing diaspora comment signature', LOGGER_DEBUG);
    $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname();
    $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
    /** @FIXME $uprvkey is undefined, do we still need this if-statement? */
    if ($uprvkey !== false) {
        $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256'));
    } else {
        $authorsig = '';
    }
    $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig));
    $key = get_config('system', 'pubkey');
    $y = crypto_encapsulate(json_encode($x), $key);
    $r = q("update item set diaspora_meta = '%s' where id = %d", dbesc(json_encode($y)), intval($post_id));
    if (!$r) {
        logger('store_diaspora_comment_sig: DB write failed');
    }
    return;
}
Beispiel #3
0
function diaspora_post_local(&$a, &$item)
{
    /**
     * If all the conditions are met, generate an instance of the Diaspora Comment Virus
     *
     * Previously all comments from any Hubzilla source (including those who have not opted in to
     * Diaspora federation), were required to locally generate a Diaspora comment signature.
     * The only exception was wall-to-wall posts which have no local signing authority.
     *
     * Going forward, if we are asked to propagate the virus and it is not present (due to the post author
     * not opting in to Diaspora federation); we will generate a "wall-to-wall" comment and not require 
     * a source signature. This allows hubs and communities to opt-out of Diaspora federation and not be
     * forced to generate the comment virus regardless. This is necessary because Diaspora now requires
     * the virus not just to provide a stored signature and Diaspora formatted text body, but must also 
     * include all XML fields presented by the Diaspora protocol when transmitting the comment, while
     * maintaining their source order. This is fine for federated communities using UNO, but it makes 
     * no sense to require this low-level baggage in channels and communities that have chosen not to use
     * the Diaspora protocol and services.
     *   
     */
    require_once 'include/bb2diaspora.php';
    if ($item['mid'] === $item['parent_mid']) {
        return;
    }
    if ($item['created'] != $item['edited']) {
        return;
    }
    $meta = null;
    $author = channelx_by_hash($item['author_xchan']);
    if ($author) {
        // The author has a local channel, If they have this connector installed,
        // sign the comment and create a Diaspora Comment Virus.
        $dspr_allowed = get_pconfig($author['channel_id'], 'system', 'diaspora_allowed');
        if (!$dspr_allowed) {
            return;
        }
        $handle = channel_reddress($author);
        if ($item['verb'] === ACTIVITY_LIKE) {
            if ($item['thr_parent'] == $item['parent_mid'] && $item['obj_type'] == ACTIVITY_OBJ_NOTE) {
                $meta = ['positive' => 'true', 'guid' => $item['mid'], 'target_type' => 'Post', 'parent_guid' => $item['parent_mid'], 'diaspora_handle' => $handle];
            }
        } else {
            $body = bb2diaspora_itembody($item, true, true);
            $meta = ['guid' => $item['mid'], 'parent_guid' => $item['parent_mid'], 'text' => $body, 'diaspora_handle' => $handle];
        }
        $meta['author_signature'] = diaspora_sign_fields($meta, $author['channel_prvkey']);
        if ($item['author_xchan'] === $item['owner_xchan']) {
            $meta['parent_author_signature'] = diaspora_sign_fields($meta, $author['channel_prvkey']);
        }
    }
    if (!$meta && $item['author_xchan'] !== $item['owner_xchan']) {
        // A local comment arrived but the commenter does not have a local channel
        // or the commenter doesn't have the Diaspora plugin enabled.
        // The owner *should* have a local channel
        // Find the owner and if the owner has this addon installed, turn the comment into
        // a 'wall-to-wall' message containing the author attribution,
        // with the comment signed by the owner.
        $owner = channelx_by_hash($item['owner_xchan']);
        if (!$owner) {
            return;
        }
        $dspr_allowed = get_pconfig($owner['channel_id'], 'system', 'diaspora_allowed');
        if (!$dspr_allowed) {
            return;
        }
        $handle = channel_reddress($owner);
        if ($item['verb'] === ACTIVITY_LIKE) {
            if ($item['thr_parent'] == $item['parent_mid'] && $item['obj_type'] == ACTIVITY_OBJ_NOTE) {
                $meta = ['positive' => 'true', 'guid' => $item['mid'], 'target_type' => 'Post', 'parent_guid' => $item['parent_mid'], 'diaspora_handle' => $handle];
            }
        } else {
            $body = bb2diaspora_itembody($item, true, false);
            $meta = ['guid' => $item['mid'], 'parent_guid' => $item['parent_mid'], 'text' => $body, 'diaspora_handle' => $handle];
        }
        $meta['author_signature'] = diaspora_sign_fields($meta, $owner['channel_prvkey']);
        $meta['parent_author_signature'] = diaspora_sign_fields($meta, $owner['channel_prvkey']);
    }
    if ($meta) {
        set_iconfig($item, 'diaspora', 'fields', $meta, true);
    }
    // otherwise, neither the author or owner have this plugin installed. Do nothing.
    // 	logger('ditem: ' . print_r($item,true));
}
Beispiel #4
0
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);
}
Beispiel #5
0
function diaspora_build_status($item, $owner)
{
    $myaddr = channel_reddress($owner);
    if (intval($item['id']) != intval($item['parent'])) {
        logger('attempted to send a comment as a top-level post');
        return;
    }
    $images = array();
    $title = $item['title'];
    $body = bb2diaspora_itembody($item, true);
    $poll = '';
    $public = $item['item_private'] ? 'false' : 'true';
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    // Detect a share element and do a reshare
    if (!$item['item_private'] && ($ret = diaspora_is_reshare($item['body']))) {
        $msg = replace_macros(get_markup_template('diaspora_reshare.tpl', 'addon/diaspora'), ['$root_handle' => xmlify($ret['root_handle']), '$root_guid' => $ret['root_guid'], '$guid' => $item['mid'], '$handle' => xmlify($myaddr), '$public' => $public, '$created' => $created, '$provider' => $item['app'] ? $item['app'] : t('$projectname')]);
    } else {
        $msg = replace_macros(get_markup_template('diaspora_post.tpl', 'addon/diaspora'), ['$body' => xmlify($body), '$guid' => $item['mid'], '$poll' => $poll, '$handle' => xmlify($myaddr), '$public' => $public, '$created' => $created, '$provider' => $item['app'] ? $item['app'] : t('$projectname')]);
    }
    return $msg;
}
function diaspora_send_downstream($item, $owner, $contact, $public_batch = false)
{
    $a = get_app();
    $myaddr = $owner['channel_address'] . '@' . App::get_hostname();
    $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
    // That version is now dead so detect a "sublike" and
    // just send it as an activity.
    $sublike = false;
    if ($item['verb'] === ACTIVITY_LIKE) {
        if ($item['thr_parent'] && $item['thr_parent'] !== $item['parent_mid']) {
            $sublike = true;
        }
    }
    // 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_downstream: no parent');
        return;
    }
    $xmlout = diaspora_fields_to_xml(get_iconfig($item, 'diaspora', 'fields'));
    $like = false;
    $relay_retract = false;
    $sql_sign_id = 'iid';
    if (intval($item['item_deleted'])) {
        $relay_retract = true;
        $target_type = $item['verb'] === ACTIVITY_LIKE && !$sublike ? 'Like' : 'Comment';
        $sql_sign_id = 'retract_iid';
        $tpl = get_markup_template('diaspora_relayable_retraction.tpl', 'addon/diaspora');
    } elseif ($item['verb'] === ACTIVITY_LIKE && !$sublike && $xmlout) {
        $like = true;
        $target_type = $parent['mid'] === $parent['parent_mid'] ? 'Post' : 'Comment';
        //		$positive = (intval($item['item_deleted']) ? 'false' : 'true');
        $positive = 'true';
        $tpl = get_markup_template('diaspora_like_relay.tpl', 'addon/diaspora');
    } else {
        // item is a comment
        $tpl = get_markup_template('diaspora_comment_relay.tpl', 'addon/diaspora');
    }
    $diaspora_meta = $item['diaspora_meta'] ? json_decode($item['diaspora_meta'], true) : '';
    if ($diaspora_meta) {
        if (array_key_exists('iv', $diaspora_meta)) {
            $key = get_config('system', 'prvkey');
            $meta = json_decode(crypto_unencapsulate($diaspora_meta, $key), true);
        } else {
            $meta = $diaspora_meta;
        }
        $sender_signed_text = $meta['signed_text'];
        $authorsig = $meta['signature'];
        $handle = $meta['signer'];
        $text = $meta['body'];
    } else {
        logger('diaspora_send_downstream: 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) {
        $handle = $owner['channel_address'] . '@' . App::get_hostname();
    }
    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;
        }
    }
    // The relayable may have arrived from somebody who provided no Diaspora Comment Virus.
    // We check for this above in bb2diaspora_itembody. In that case we will have generated
    // the body as a "wall-to-wall" post, and the author_signature will now be our own.
    if (!$xmlout && !$authorsig) {
        $authorsig = base64_encode(rsa_sign($sender_signed_text, $owner['channel_prvkey'], 'sha256'));
    }
    // Sign the relayable with the top-level owner's signature
    $parentauthorsig = base64_encode(rsa_sign($sender_signed_text, $owner['channel_prvkey'], 'sha256'));
    if (!$text) {
        logger('diaspora_send_downstream: no text');
    }
    $msg = replace_macros($tpl, array('$xml' => $xmlout, '$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_downstream: 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_queue($owner, $contact, $slap, $public_batch, $item['mid']);
}