= 400) $err = 'Error'; if($val >= 200 && $val < 300) $err = 'OK'; logger('mod-salmon returns ' . $val); header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err); killme(); } function salmon_post(&$a) { $xml = file_get_contents('php://input'); logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA); $nick = ((argc() > 1) ? trim(argv(1)) : ''); // $mentions = (($a->argc > 2 && $a->argv[2] === 'mention') ? true : false); $importer = channelx_by_nick($nick); if(! $importer) http_status_exit(500); // @fixme check that this channel has the GNU-Social protocol enabled // parse the xml $dom = simplexml_load_string($xml,'SimpleXMLElement',0,NAMESPACE_SALMON_ME); // figure out where in the DOM tree our data is hiding if($dom->provenance->data) $base = $dom->provenance; elseif($dom->env->data) $base = $dom->env; elseif($dom->data) $base = $dom; if(! $base) { logger('mod-salmon: unable to locate salmon data in xml '); http_status_exit(400); } logger('data: ' . $xml, LOGGER_DATA); // Stash the signature away for now. We have to find their key or it won't be good for anything. $signature = base64url_decode($base->sig); // unpack the data // strip whitespace so our data element will return to one big base64 blob $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data); // stash away some other stuff for later $type = $base->data[0]->attributes()->type[0]; $keyhash = $base->sig[0]->attributes()->keyhash[0]; $encoding = $base->encoding; $alg = $base->alg; // Salmon magic signatures have evolved and there is no way of knowing ahead of time which // flavour we have. We'll try and verify it regardless. $stnet_signed_data = $data; $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg); $compliant_format = str_replace('=','',$signed_data); // decode the data $data = base64url_decode($data); logger('decoded: ' . $data, LOGGER_DATA); // GNU-Social doesn't send a legal Atom feed over salmon, only an Atom entry. Unfortunately // our parser is a bit strict about compliance so we'll insert just enough of a feed // tag to trick it into believing it's a compliant feed. if(! strstr($data,' NOTIFY_INTRO, 'from_xchan' => $xchan['xchan_hash'], 'to_xchan' => $importer['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], )); if($default_perms) { // @fixme!!! // Send back a sharing notification to them $x = gnusoc_follow($importer,$new_connection[0]); if($x) proc_run('php','include/deliver.php',$x); } $clone = array(); foreach($new_connection[0] as $k => $v) { if(strpos($k,'abook_') === 0) { $clone[$k] = $v; } } unset($clone['abook_id']); unset($clone['abook_account']); unset($clone['abook_channel']); $abconfig = load_abconfig($importer['channel_hash'],$clone['abook_xchan']); if($abconfig) $clone['abconfig'] = $abconfig; build_sync_packet($importer['channel_id'], array('abook' => array($clone))); } http_status_exit(200); } } } // // ... fixme // Otherwise check general permissions if(! perm_is_allowed($importer['channel_id'],$xchan['xchan_hash'],'send_stream')) { // check for and process ostatus autofriend // ... fixme // otherwise logger('mod-salmon: Ignoring this author.'); http_status_exit(202); // NOTREACHED } unset($datarray['author']); $parent_item = null; if($datarray['parent_mid']) { $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($datarray['parent_mid']), intval($importer['channel_id']) ); if(! $r) { logger('mod-salmon: parent item not found.'); http_status_exit(202); } $parent_item = $r[0]; } if(! $datarray['author_xchan']) $datarray['author_xchan'] = $xchan['xchan_hash']; $datarray['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $xchan['xchan_hash']); $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($datarray['mid']), intval($importer['channel_id']) ); // Update content if 'updated' changes // currently a no-op @fixme if($r) { if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) { // do not accept (ignore) an earlier edit than one we currently have. if(datetime_convert('UTC','UTC',$datarray['edited']) > $r[0]['edited']) update_feed_item($importer['channel_id'],$datarray); } http_status_exit(200); } if(! $datarray['parent_mid']) $datarray['parent_mid'] = $datarray['mid']; $datarray['aid'] = $importer['channel_account_id']; $datarray['uid'] = $importer['channel_id']; logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); $xx = item_store($datarray); $r = $xx['item_id']; // if this is a reply, do a relay? http_status_exit(200); } function gnusoc_follow($importer,$xchan) { }