function handle_pubsubhubbub() { global $a, $db; logger('start'); // We'll push to each subscriber that has push > 0, // i.e. there has been an update (set in notifier.php). $r = q("SELECT * FROM `push_subscriber` WHERE `push` > 0"); foreach ($r as $rr) { $params = get_feed_for($a, '', $rr['nickname'], $rr['last_update'], 0, true); $hmac_sig = hash_hmac("sha1", $params, $rr['secret']); $headers = array("Content-type: application/atom+xml", sprintf("Link: <%s>;rel=hub," . "<%s>;rel=self", $a->get_baseurl() . '/pubsubhubbub', $rr['topic']), "X-Hub-Signature: sha1=" . $hmac_sig); logger('POST ' . print_r($headers, true) . "\n" . $params, LOGGER_DEBUG); post_url($rr['callback_url'], $params, $headers); $ret = $a->get_curl_code(); if ($ret >= 200 && $ret <= 299) { logger('successfully pushed to ' . $rr['callback_url']); // set last_update to "now", and reset push=0 $date_now = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s'); q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d", dbesc($date_now), intval($rr['id'])); } else { logger('error when pushing to ' . $rr['callback_url'] . ' HTTP: ' . $ret); // we use the push variable also as a counter, if we failed we // increment this until some upper limit where we give up $new_push = intval($rr['push']) + 1; if ($new_push > 30) { // OK, let's give up $new_push = 0; } q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d", $new_push, intval($rr['id'])); } } logger('done'); }
function push_notifier_process(&$a, &$b) { logger('push_notifier_process'); if (!$b['normal_mode']) { return; } if ($b['private'] || $b['packet_type'] !== 'undefined' || $b['mail']) { return; } if (!$b['top_level_post']) { return; } // find push_subscribers following this $owner $channel = $b['channel']; // allow subscriptions either by http or https, as gnu-social has been known to subscribe // to the wrong one. $r = q("select * from push_subscriber where topic like '%s'", dbesc('%://' . App::get_hostname() . '/feed/' . $channel['channel_address'])); if (!$r) { return; } foreach ($r as $rr) { $feed = get_feed_for($channel, '', array('begin' => $rr['last_update'])); $hmac_sig = hash_hmac("sha1", $feed, $rr['secret']); $slap = array('sig' => $hmac_sig, 'topic' => $rr['topic'], 'body' => $feed); // Check for public post and create atom wrapper and stick in queue // also need queue driver for 'push' since we need to set some extra headers $hash = random_string(); queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'driver' => 'push', 'posturl' => $rr['callback_url'], 'notify' => '', 'msg' => json_encode($slap))); $b['queued'][] = $hash; } }
/** * @brief Generate an Atom feed. * * @param array $channel * @param array $params */ function get_public_feed($channel, $params) { $type = 'xml'; $begin = NULL_DATE; $end = ''; $start = 0; $records = 40; $direction = 'desc'; $pages = 0; if (!$params) { $params = array(); } $params['type'] = x($params, 'type') ? $params['type'] : 'xml'; $params['begin'] = x($params, 'begin') ? $params['begin'] : NULL_DATE; $params['end'] = x($params, 'end') ? $params['end'] : datetime_convert('UTC', 'UTC', 'now'); $params['start'] = x($params, 'start') ? $params['start'] : 0; $params['records'] = x($params, 'records') ? $params['records'] : 40; $params['direction'] = x($params, 'direction') ? $params['direction'] : 'desc'; $params['pages'] = x($params, 'pages') ? intval($params['pages']) : 0; $params['top'] = x($params, 'top') ? intval($params['top']) : 0; $params['cat'] = x($params, 'cat') ? $params['cat'] : ''; // put a sane lower limit on feed requests if not specified // if($params['begin'] === NULL_DATE) // $params['begin'] = datetime_convert('UTC','UTC','now - 1 month'); switch ($params['type']) { case 'json': header("Content-type: application/atom+json"); break; case 'xml': default: header("Content-type: application/atom+xml"); break; } return get_feed_for($channel, get_observer_hash(), $params); }
function dfrn_poll_post(&$a) { $dfrn_id = x($_POST, 'dfrn_id') ? $_POST['dfrn_id'] : ''; $challenge = x($_POST, 'challenge') ? $_POST['challenge'] : ''; $url = x($_POST, 'url') ? $_POST['url'] : ''; $sec = x($_POST, 'sec') ? $_POST['sec'] : ''; $ptype = x($_POST, 'type') ? $_POST['type'] : ''; $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0; $perm = x($_POST, 'perm') ? $_POST['perm'] : 'r'; if ($ptype === 'profile-check') { if (strlen($challenge) && strlen($sec)) { logger('dfrn_poll: POST: profile-check'); q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time())); $r = q("SELECT * FROM `profile_check` WHERE `sec` = '%s' ORDER BY `expire` DESC LIMIT 1", dbesc($sec)); if (!count($r)) { xml_status(3, 'No ticket'); // NOTREACHED } $orig_id = $r[0]['dfrn_id']; if (strpos($orig_id, ':')) { $orig_id = substr($orig_id, 2); } $c = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($r[0]['cid'])); if (!count($c)) { xml_status(3, 'No profile'); } $contact = $c[0]; $sent_dfrn_id = hex2bin($dfrn_id); $challenge = hex2bin($challenge); $final_dfrn_id = ''; if ($contact['duplex'] && strlen($contact['prvkey'])) { openssl_private_decrypt($sent_dfrn_id, $final_dfrn_id, $contact['prvkey']); openssl_private_decrypt($challenge, $decoded_challenge, $contact['prvkey']); } else { openssl_public_decrypt($sent_dfrn_id, $final_dfrn_id, $contact['pubkey']); openssl_public_decrypt($challenge, $decoded_challenge, $contact['pubkey']); } $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); if (strpos($final_dfrn_id, ':') == 1) { $final_dfrn_id = substr($final_dfrn_id, 2); } if ($final_dfrn_id != $orig_id) { logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG); // did not decode properly - cannot trust this site xml_status(3, 'Bad decryption'); } header("Content-type: text/xml"); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dfrn_poll><status>0</status><challenge>{$decoded_challenge}</challenge><sec>{$sec}</sec></dfrn_poll>"; killme(); // NOTREACHED } } $direction = -1; if (strpos($dfrn_id, ':') == 1) { $direction = intval(substr($dfrn_id, 0, 1)); $dfrn_id = substr($dfrn_id, 2); } $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); if (!count($r)) { killme(); } $type = $r[0]['type']; $last_update = $r[0]['last_update']; $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); $sql_extra = ''; switch ($direction) { case -1: $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); $my_id = $dfrn_id; break; case 0: $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); $my_id = '1:' . $dfrn_id; break; case 1: $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); $my_id = '0:' . $dfrn_id; break; default: goaway(z_root()); break; // NOTREACHED } $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 {$sql_extra} LIMIT 1"); if (!count($r)) { killme(); } $contact = $r[0]; $owner_uid = $r[0]['uid']; $contact_id = $r[0]['id']; if ($type === 'reputation' && strlen($url)) { $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($url), intval($owner_uid)); $reputation = 0; $text = ''; if (count($r)) { $reputation = $r[0]['rating']; $text = $r[0]['reason']; if ($r[0]['id'] == $contact_id) { // inquiring about own reputation not allowed $reputation = 0; $text = ''; } } echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t<reputation>\n\t\t\t<url>{$url}</url>\n\t\t\t<rating>{$reputation}</rating>\n\t\t\t<description>{$text}</description>\n\t\t</reputation>\n\t\t"; killme(); // NOTREACHED } else { // Update the writable flag if it changed logger('dfrn_poll: post request feed: ' . print_r($_POST, true), LOGGER_DATA); if ($dfrn_version >= 2.21) { if ($perm === 'rw') { $writable = 1; } else { $writable = 0; } if ($writable != $contact['writable']) { q("UPDATE `contact` SET `writable` = %d WHERE `id` = %d LIMIT 1", intval($writable), intval($contact_id)); } } header("Content-type: application/atom+xml"); $o = get_feed_for($a, $dfrn_id, $a->argv[1], $last_update, $direction); echo $o; killme(); } }
function dfrn_poll_post(&$a) { $dfrn_id = notags(trim($_POST['dfrn_id'])); $challenge = notags(trim($_POST['challenge'])); $url = $_POST['url']; $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); if (!count($r)) { killme(); } $type = $r[0]['type']; $last_update = $r[0]['last_update']; $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); $r = q("SELECT * FROM `contact` WHERE ( `issued-id` = '%s' OR ( `dfrn-id` = '%s' AND `duplex` = 1 )) LIMIT 1", dbesc($dfrn_id), dbesc($dfrn_id)); if (!count($r)) { killme(); } $contact_id = $r[0]['id']; if ($type == 'reputation' && strlen($url)) { $r = q("SELECT * FROM `contact` WHERE `url` = '%s' LIMIT 1", dbesc($url)); $reputation = 0; $text = ''; if (count($r)) { $reputation = $r[0]['rating']; $text = $r[0]['reason']; if ($r[0]['id'] == $contact_id) { // inquiring about own reputation not allowed $reputation = 0; $text = ''; } } echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t<reputation>\n\t\t\t<url>{$url}</url>\n\t\t\t<rating>{$reputation}</rating>\n\t\t\t<description>{$text}</description>\n\t\t</reputation>\n\t\t"; killme(); return; // NOTREACHED } else { $o = get_feed_for($a, $dfrn_id, $a->argv[1], $last_update); echo $o; killme(); } }