diaspora continued...

This commit is contained in:
Friendika 2011-08-17 04:24:26 -07:00
parent 673e114bbd
commit db03b1ab17

View file

@ -114,15 +114,29 @@ EOT;
} }
/**
*
* diaspora_decode($importer,$xml)
* array $importer -> from user table
* string $xml -> urldecoded Diaspora salmon
*
* Returns array
* 'message' -> decoded Diaspora XML message
* 'author' -> author diaspora handle
* 'key' -> author public key (converted to pkcs#8)
*
* Author and key are used elsewhere to save a lookup for verifying replies and likes
*/
function diaspora_decode($importer,$xml) { function diaspora_decode($importer,$xml) {
$basedom = parse_xml_string($xml); $basedom = parse_xml_string($xml);
$atom = $basedom->children(NAMESPACE_ATOM1); $atom = $basedom->children(NAMESPACE_ATOM1);
// Diaspora devs: This is kind of sucky - 'encrypted_header' does not belong in the atom namespace
$encrypted_header = json_decode(base64_decode($atom->encrypted_header)); $encrypted_header = json_decode(base64_decode($atom->encrypted_header));
$encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key); $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
@ -185,7 +199,14 @@ function diaspora_decode($importer,$xml) {
// strip whitespace so our data element will return to one big base64 blob // strip whitespace so our data element will return to one big base64 blob
$data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data); $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
// Add back the 60 char linefeeds // Add back the 60 char linefeeds
// Diaspora devs: This completely violates the entire principle of salmon magic signatures,
// which was to have a message signing format that was completely ambivalent to linefeeds
// and transport whitespace mangling, and base64 wrapping rules. Guess what? PHP and Ruby
// use different linelengths for base64 output.
$lines = str_split($data,60); $lines = str_split($data,60);
$data = implode("\n",$lines); $data = implode("\n",$lines);
@ -197,6 +218,8 @@ function diaspora_decode($importer,$xml) {
$encoding = $base->encoding; $encoding = $base->encoding;
$alg = $base->alg; $alg = $base->alg;
// Diaspora devs: I can't even begin to tell you how sucky this is. Read the freaking spec.
$signed_data = $data . (($data[-1] != "\n") ? "\n" : '') . '.' . base64url_encode($type) . "\n" . '.' . base64url_encode($encoding) . "\n" . '.' . base64url_encode($alg) . "\n"; $signed_data = $data . (($data[-1] != "\n") ? "\n" : '') . '.' . base64url_encode($type) . "\n" . '.' . base64url_encode($encoding) . "\n" . '.' . base64url_encode($alg) . "\n";
@ -255,6 +278,20 @@ function diaspora_get_contact_by_handle($uid,$handle) {
return false; return false;
} }
function find_person_by_handle($handle) {
// we don't care about the uid, we just want to save an expensive webfinger probe
$r = q("select * from contact where network = '%s' and addr = '%s' LIMIT 1",
dbesc(NETWORK_DIASPORA),
dbesc($handle)
);
if(count($r))
return $r[0];
$r = probe_url($handle);
// need to cached this, perhaps in fcontact
if(count($r))
return ($r);
return false;
}
function diaspora_request($importer,$xml) { function diaspora_request($importer,$xml) {
@ -266,7 +303,12 @@ function diaspora_request($importer,$xml) {
$contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle); $contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
if($contact) { if($contact) {
// perhaps we were already sharing with this person. Now they're sharing with us.
// That makes us friends.
if($contact['rel'] == CONTACT_IS_FOLLOWER) { if($contact['rel'] == CONTACT_IS_FOLLOWER) {
q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval(CONTACT_IS_FRIEND), intval(CONTACT_IS_FRIEND),
@ -414,11 +456,19 @@ function diaspora_post($importer,$xml) {
} }
function diaspora_comment($importer,$xml,$msg) { function diaspora_comment($importer,$xml,$msg) {
$guid = notags(unxmlify($xml->guid)); $guid = notags(unxmlify($xml->guid));
$parent_guid = notags(unxmlify($xml->parent_guid));
$diaspora_handle = notags(unxmlify($xml->diaspora_handle)); $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
$target_type = notags(unxmlify($xml->target_type));
$text = unxmlify($xml->text);
$author_signature = notags(unxmlify($xml->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); $text = $xml->text;
$contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
if(! $contact) if(! $contact)
return; return;
@ -428,24 +478,109 @@ function diaspora_comment($importer,$xml,$msg) {
// NOTREACHED // NOTREACHED
} }
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer['uid']),
dbesc($parent_guid)
);
if(! count($r)) {
logger('diaspora_comment: parent item not found: ' . $guid);
return;
}
$parent_item = $r[0];
$author_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle;
$author_signature = base64_decode($author_signature);
if(stricmp($diaspora_handle,$msg['author']) == 0) {
$person = $contact;
$key = $msg['key'];
}
else {
$person = find_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(! rsa_verify($author_signed_data,$author_signature,$key)) {
logger('diaspora_comment: verification failed.');
return;
}
if($parent_author_signature) {
$owner_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $msg['author'];
$parent_author_signature = base64_decode($parent_author_signature);
$key = $msg['key'];
if(! rsa_verify($owner_signed_data,$parent_author_signature,$key)) {
logger('diaspora_comment: owner verification failed.');
return;
}
}
// Phew! Everything checks out. Now create an item.
require_once('library/HTMLPurifier.auto.php');
require_once('include/html2bbcode.php');
$body = $text;
$maxlen = get_max_import_size();
if($maxlen && (strlen($body) > $maxlen))
$body = substr($body,0, $maxlen);
if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
$body = preg_replace('#<object[^>]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s',
'[youtube]$1[/youtube]', $body);
$body = preg_replace('#<iframe[^>].+?' . 'http://www.youtube.com/embed/([A-Za-z0-9\-_=]+).+?</iframe>#s',
'[youtube]$1[/youtube]', $body);
$body = oembed_html2bbcode($body);
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
$purifier = new HTMLPurifier($config);
$body = $purifier->purify($body);
$body = html2bbcode($body);
}
$message_id = $diaspora_handle . ':' . $guid; $message_id = $diaspora_handle . ':' . $guid;
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
intval($importer['uid']),
dbesc($guid)
);
if(! count($r))
return;
$owner = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", $datarray = array();
intval($importer['uid']) $datarray['uid'] = $importer['uid'];
); $datarray['contact-id'] = $contact['id'];
if(! count($owner)) $datarray['wall'] = $parent_item['wall'];
return; $datarray['gravity'] = GRAVITY_COMMENT;
$datarray['guid'] = $guid;
$datarray['uri'] = $message_id;
$datarray['parent-uri'] = $parent_item['uri'];
$created = unxmlify($xml->created_at); // No timestamps for comments? OK, we'll the use current time.
$private = ((unxmlify($xml->public) == 'false') ? 1 : 0); $datarray['created'] = $datarray['edited'] = datetime_convert();
$datarray['private'] = $parent_item['private'];
$datarray['owner-name'] = $contact['name'];
$datarray['owner-link'] = $contact['url'];
$datarray['owner-avatar'] = $contact['thumb'];
$datarray['author-name'] = $person['name'];
$datarray['author-link'] = $person['url'];
$datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$datarray['body'] = $body;
item_store($datarray);
return;
} }
@ -456,14 +591,16 @@ function diaspora_like($importer,$xml,$msg) {
$diaspora_handle = notags(unxmlify($xml->diaspora_handle)); $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
$target_type = notags(unxmlify($xml->target_type)); $target_type = notags(unxmlify($xml->target_type));
$positive = notags(unxmlify($xml->positive)); $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)) : ''); $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : '');
// likes on comments not supported here // likes on comments not supported here and likes on photos not supported by Diaspora
if($target_type !== 'Post') if($target_type !== 'Post')
return; return;
$contact = diaspora_get_contact_by_handle($importer['uid'],$msg->author); $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
if(! $contact) if(! $contact)
return; return;
@ -512,10 +649,19 @@ function diaspora_like($importer,$xml,$msg) {
$author_signature = base64_decode($author_signature); $author_signature = base64_decode($author_signature);
if(stricmp($diaspora_handle,$msg['author']) == 0) if(stricmp($diaspora_handle,$msg['author']) == 0) {
$person = $contact;
$key = $msg['key']; $key = $msg['key'];
else }
$key = get_diaspora_key($diaspora_handle); else {
$person = find_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(! rsa_verify($author_signed_data,$author_signature,$key)) { if(! rsa_verify($author_signed_data,$author_signature,$key)) {
logger('diaspora_like: verification failed.'); logger('diaspora_like: verification failed.');
@ -539,6 +685,7 @@ function diaspora_like($importer,$xml,$msg) {
$uri = $diaspora_handle . ':' . $guid; $uri = $diaspora_handle . ':' . $guid;
$activity = ACTIVITY_LIKE;
$post_type = (($parent_item['resource-id']) ? t('photo') : t('status')); $post_type = (($parent_item['resource-id']) ? t('photo') : t('status'));
$objtype = (($parent_item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); $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") ; $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n") ;
@ -568,26 +715,23 @@ EOT;
$arr['parent'] = $parent_item['id']; $arr['parent'] = $parent_item['id'];
$arr['parent-uri'] = $parent_item['uri']; $arr['parent-uri'] = $parent_item['uri'];
// $arr['owner-name'] = $owner['name']; // FIXME $datarray['owner-name'] = $contact['name'];
// $arr['owner-link'] = $owner['url']; $datarray['owner-link'] = $contact['url'];
// $arr['owner-avatar'] = $owner['thumb']; $datarray['owner-avatar'] = $contact['thumb'];
$arr['author-name'] = $contact['name']; $datarray['author-name'] = $person['name'];
$arr['author-link'] = $contact['url']; $datarray['author-link'] = $person['url'];
$arr['author-avatar'] = $contact['thumb']; $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']);
$ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
$alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-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/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
$arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink );
$arr['private'] = $parent_item['private'];
$arr['verb'] = $activity; $arr['verb'] = $activity;
$arr['object-type'] = $objtype; $arr['object-type'] = $objtype;
$arr['object'] = $obj; $arr['object'] = $obj;
$arr['allow_cid'] = $parent_item['allow_cid'];
$arr['allow_gid'] = $parent_item['allow_gid'];
$arr['deny_cid'] = $parent_item['deny_cid'];
$arr['deny_gid'] = $parent_item['deny_gid'];
$arr['visible'] = 1; $arr['visible'] = 1;
$arr['unseen'] = 1; $arr['unseen'] = 1;
$arr['last-child'] = 0; $arr['last-child'] = 0;