]> git.mxchange.org Git - friendica.git/commitdiff
diaspora continued...
authorFriendika <info@friendika.com>
Wed, 17 Aug 2011 11:24:26 +0000 (04:24 -0700)
committerFriendika <info@friendika.com>
Wed, 17 Aug 2011 11:24:26 +0000 (04:24 -0700)
include/diaspora.php

index 0764dfa4ae8945b5f2749be6bc6e8601f9cb9168..e089e3f040e8c6977850ebca241c9262ceda871b 100644 (file)
@@ -114,15 +114,29 @@ EOT;
 
 }
 
-
-function diaspora_decode($importer,$xml) {
+/**
+ *
+ * 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) {
 
        $basedom = parse_xml_string($xml);
 
        $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_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
        $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
+
        // 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);
     $data = implode("\n",$lines);
 
@@ -197,6 +218,8 @@ function diaspora_decode($importer,$xml) {
        $encoding = $base->encoding;
        $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";
 
 
@@ -255,6 +278,20 @@ function diaspora_get_contact_by_handle($uid,$handle) {
        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) {
 
@@ -266,7 +303,12 @@ function diaspora_request($importer,$xml) {
         
        $contact = diaspora_get_contact_by_handle($importer['uid'],$sender_handle);
 
+
        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) {
                        q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1",
                                intval(CONTACT_IS_FRIEND),
@@ -414,11 +456,19 @@ function diaspora_post($importer,$xml) {
 }
 
 function diaspora_comment($importer,$xml,$msg) {
+
        $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));
+       $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)
                return;
 
@@ -428,24 +478,109 @@ function diaspora_comment($importer,$xml,$msg) {
                // NOTREACHED
        }
 
-
-
-       $message_id = $diaspora_handle . ':' . $guid;
-       $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
+       $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
                intval($importer['uid']),
-               dbesc($guid)
+               dbesc($parent_guid)
        );
-       if(! count($r))
+       if(! count($r)) {
+               logger('diaspora_comment: parent item not found: ' . $guid);
                return;
+       }
+       $parent_item = $r[0];
 
-       $owner = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1",
-               intval($importer['uid'])
-       );
-       if(! count($owner))
+       $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;
+       }
 
-       $created = unxmlify($xml->created_at);
-       $private = ((unxmlify($xml->public) == 'false') ? 1 : 0);
+       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;
+
+       $datarray = array();
+       $datarray['uid'] = $importer['uid'];
+       $datarray['contact-id'] = $contact['id'];
+       $datarray['wall'] = $parent_item['wall'];
+       $datarray['gravity'] = GRAVITY_COMMENT;
+       $datarray['guid'] = $guid;
+       $datarray['uri'] = $message_id;
+       $datarray['parent-uri'] = $parent_item['uri'];
+
+       // No timestamps for comments? OK, we'll the use current time.
+       $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));
        $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
+       // 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);
+       $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']);
        if(! $contact)
                return;
 
@@ -512,10 +649,19 @@ function diaspora_like($importer,$xml,$msg) {
 
        $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'];
-       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)) {
                logger('diaspora_like: verification failed.');
@@ -539,6 +685,7 @@ function diaspora_like($importer,$xml,$msg) {
 
        $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") ;
@@ -568,26 +715,23 @@ EOT;
        $arr['parent'] = $parent_item['id'];
        $arr['parent-uri'] = $parent_item['uri'];
 
-//     $arr['owner-name'] = $owner['name']; // FIXME
-//     $arr['owner-link'] = $owner['url'];
-//     $arr['owner-avatar'] = $owner['thumb'];
+       $datarray['owner-name'] = $contact['name'];
+       $datarray['owner-link'] = $contact['url'];
+       $datarray['owner-avatar'] = $contact['thumb'];
 
-       $arr['author-name'] = $contact['name'];
-       $arr['author-link'] = $contact['url'];
-       $arr['author-avatar'] = $contact['thumb'];
+       $datarray['author-name'] = $person['name'];
+       $datarray['author-link'] = $person['url'];
+       $datarray['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['private'] = $parent_item['private'];
        $arr['verb'] = $activity;
        $arr['object-type'] = $objtype;
        $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['unseen'] = 1;
        $arr['last-child'] = 0;