Esempio n. 1
0
function diaspora_like($importer, $xml, $msg)
{
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $parent_guid = notags(unxmlify($xml->parent_guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $target_type = notags(unxmlify($xml->target_type));
    $positive = notags(unxmlify($xml->positive));
    $author_signature = notags(unxmlify($xml->author_signature));
    $parent_author_signature = $xml->parent_author_signature ? notags(unxmlify($xml->parent_author_signature)) : '';
    // likes on comments not supported here and likes on photos not supported by Diaspora
    //	if($target_type !== 'Post')
    //		return;
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_like: cannot find contact: ' . $msg['author']);
        return;
    }
    if (!diaspora_post_allow($importer, $contact, false)) {
        logger('diaspora_like: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
    if (!count($r)) {
        $result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
        if (!$result) {
            $person = find_diaspora_person_by_handle($diaspora_handle);
            $result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
        }
        if ($result) {
            logger("Fetched missing item " . $parent_guid . " - result: " . $result, LOGGER_DEBUG);
            $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
        }
    }
    if (!count($r)) {
        logger('diaspora_like: parent item not found: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($guid));
    if (count($r)) {
        if ($positive === 'true') {
            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') {
            logger('diaspora_like: received a like with positive set to "false"...ignoring');
            /*			q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d",
            				intval($r[0]['id']),
            				intval($importer['uid'])
            			);*/
            // 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: received a like with positive set to "false"');
        logger('diaspora_like: unlike received with no corresponding like...ignoring');
        return;
    }
    /* How Diaspora performs "like" signature checking:
    
    	   - 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
    	*/
    // Diaspora has changed the way they are signing the likes.
    // Just to make sure that we don't miss any likes we will check the old and the current way.
    $old_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
    $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle;
    $key = $msg['key'];
    if ($parent_author_signature) {
        // 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);
        if (!rsa_verify($signed_data, $parent_author_signature, $key, 'sha256') and !rsa_verify($old_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($signed_data, $author_signature, $key, 'sha256') and !rsa_verify($old_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;
    $post_type = $parent_item['resource-id'] ? t('photo') : t('status');
    $objtype = $parent_item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n");
    $body = $parent_item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$parent_item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s likes %2$s\'s %3$s');
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $importer['uid'];
    $arr['guid'] = $guid;
    $arr['network'] = NETWORK_DIASPORA;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $parent_item['wall'];
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $parent_item['id'];
    $arr['parent-uri'] = $parent_item['uri'];
    $arr['owner-name'] = $parent_item['name'];
    $arr['owner-link'] = $parent_item['url'];
    //$arr['owner-avatar'] = $parent_item['thumb'];
    $arr['owner-avatar'] = x($parent_item, 'thumb') ? $parent_item['thumb'] : $parent_item['photo'];
    $arr['author-name'] = $person['name'];
    $arr['author-link'] = $person['url'];
    $arr['author-avatar'] = x($person, 'thumb') ? $person['thumb'] : $person['photo'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
    //$plink = '[url=' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . urlencode($guid) . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['app'] = 'Diaspora';
    $arr['private'] = $parent_item['private'];
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $message_id = item_store($arr);
    //if($message_id) {
    //	q("update item set plink = '%s' where id = %d",
    //		//dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
    //		dbesc($a->get_baseurl().'/display/'.$guid),
    //		intval($message_id)
    //	);
    //}
    if (!$parent_author_signature) {
        q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($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. The parent_item['origin'] indicates the message was created on our system
    if ($parent_item['origin'] && !$parent_author_signature) {
        proc_run('php', 'include/notifier.php', 'comment-import', $message_id);
    }
    return;
}
Esempio n. 2
0
function diaspora_like($importer, $xml, $msg)
{
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $parent_guid = notags(unxmlify($xml->parent_guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $target_type = notags(unxmlify($xml->target_type));
    $positive = notags(unxmlify($xml->positive));
    $author_signature = notags(unxmlify($xml->author_signature));
    $parent_author_signature = $xml->parent_author_signature ? notags(unxmlify($xml->parent_author_signature)) : '';
    // likes on comments not supported here and likes on photos not supported by Diaspora
    if ($target_type !== 'Post') {
        return;
    }
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_like: cannot find contact: ' . $msg['author']);
        return;
    }
    if (!diaspora_post_allow($importer, $contact)) {
        logger('diaspora_like: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
    if (!count($r)) {
        logger('diaspora_like: parent item not found: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($guid));
    if (count($r)) {
        if ($positive === 'true') {
            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') {
            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: received a like with positive set to "false"');
        logger('diaspora_like: unlike received with no corresponding like...ignoring');
        return;
    }
    $signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
    $author_signature = base64_decode($author_signature);
    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 (!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;
        $parent_author_signature = base64_decode($parent_author_signature);
        $key = $msg['key'];
        if (!rsa_verify($signed_data, $parent_author_signature, $key, 'sha256')) {
            logger('diaspora_like: owner verification failed.');
            return;
        }
    }
    // Phew! Everything checks out. Now create an item.
    $uri = $diaspora_handle . ':' . $guid;
    $activity = ACTIVITY_LIKE;
    $post_type = $parent_item['resource-id'] ? t('photo') : t('status');
    $objtype = $parent_item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n");
    $body = $parent_item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$parent_item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s likes %2$s\'s %3$s');
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $importer['uid'];
    $arr['guid'] = $guid;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $parent_item['wall'];
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $parent_item['id'];
    $arr['parent-uri'] = $parent_item['uri'];
    $arr['owner-name'] = $parent_item['name'];
    $arr['owner-link'] = $parent_item['url'];
    $arr['owner-avatar'] = $parent_item['thumb'];
    $arr['author-name'] = $person['name'];
    $arr['author-link'] = $person['url'];
    $arr['author-avatar'] = x($person, 'thumb') ? $person['thumb'] : $person['photo'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['app'] = 'Diaspora';
    $arr['private'] = $parent_item['private'];
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $message_id = item_store($arr);
    if ($message_id) {
        q("update item set plink = '%s' where id = %d limit 1", dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id), intval($message_id));
    }
    if (!$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. The parent_item['origin'] indicates the message was created on our system
    if ($parent_item['origin'] && !$parent_author_signature) {
        proc_run('php', 'include/notifier.php', 'comment', $message_id);
    }
    return;
}