function pubsub_post(&$a) { $sys_disabled = true; if (!get_config('system', 'disable_discover_tab')) { $sys_disabled = get_config('system', 'disable_diaspora_discover_tab'); } $sys = $sys_disabled ? null : get_sys_channel(); if ($sys) { $sys['system'] = true; } $xml = file_get_contents('php://input'); logger('pubsub: feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . App::$cmd); logger('pubsub: user-agent: ' . $_SERVER['HTTP_USER_AGENT']); logger('pubsub: data: ' . $xml, LOGGER_DATA); $nick = argc() > 1 ? escape_tags(trim(argv(1))) : ''; $contact_id = argc() > 2 ? intval(argv(2)) : 0; $channel = channelx_by_nick($nick); if (!$channel) { http_status_exit(200, 'OK'); } $importer_arr = array($channel); if ($sys) { $importer_arr[] = $sys; } foreach ($importer_arr as $channel) { if (!$channel['system']) { $connections = abook_connections($channel['channel_id'], ' and abook_id = ' . $contact_id); } else { $connections = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", intval($contact_id)); } if ($connections) { $xchan = $connections[0]; } else { logger('connection ' . $contact_id . ' not found.'); continue; } if (!perm_is_allowed($channel['channel_id'], $xchan['xchan_hash'], 'send_stream') && !$channel['system']) { logger('permission denied.'); continue; } consume_feed($xml, $channel, $xchan, 1); consume_feed($xml, $channel, $xchan, 2); } http_status_exit(200, 'OK'); }
function photos_init(&$a) { if (get_config('system', 'block_public') && !local_channel() && !remote_channel()) { return; } $o = ''; if (argc() > 1) { $nick = argv(1); profile_load($a, $nick); $channelx = channelx_by_nick($nick); if (!$channelx) { return; } $a->data['channel'] = $channelx; $observer = $a->get_observer(); $a->data['observer'] = $observer; $observer_xchan = $observer ? $observer['xchan_hash'] : ''; head_set_icon($a->data['channel']['xchan_photo_s']); $a->page['htmlhead'] .= "<script> var ispublic = '" . t('everybody') . "'; var profile_uid = " . ($a->data['channel'] ? $a->data['channel']['channel_id'] : 0) . "; </script>"; } return; }
function init() { if (observer_prohibited()) { return; } $o = ''; if (argc() > 1) { $nick = argv(1); profile_load($nick); $channelx = channelx_by_nick($nick); if (!$channelx) { return; } \App::$data['channel'] = $channelx; $observer = \App::get_observer(); \App::$data['observer'] = $observer; $observer_xchan = $observer ? $observer['xchan_hash'] : ''; head_set_icon(\App::$data['channel']['xchan_photo_s']); \App::$page['htmlhead'] .= "<script> var profile_uid = " . (\App::$data['channel'] ? \App::$data['channel']['channel_id'] : 0) . "; </script>"; } return; }
function init() { if (get_config('system', 'block_public') && !local_channel() && !remote_channel()) { return; } $o = ''; if (argc() > 1) { $nick = argv(1); profile_load($a, $nick); $channelx = channelx_by_nick($nick); if (!$channelx) { return; } \App::$data['channel'] = $channelx; $observer = \App::get_observer(); \App::$data['observer'] = $observer; $observer_xchan = $observer ? $observer['xchan_hash'] : ''; head_set_icon(\App::$data['channel']['xchan_photo_s']); \App::$page['htmlhead'] .= "<script> var profile_uid = " . (\App::$data['channel'] ? \App::$data['channel']['channel_id'] : 0) . "; </script>"; } return; }
function get() { if (observer_prohibited()) { return; } $channel = null; if (argc() > 1) { $channel = channelx_by_nick(argv(1)); } if (!$channel) { notice(t('Channel not found.') . EOL); return; } // since we don't currently have an event permission - use the stream permission if (!perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) { notice(t('Permissions denied.') . EOL); return; } $sql_extra = permissions_sql($channel['channel_id'], get_observer_hash(), 'event'); $first_day = get_pconfig(local_channel(), 'system', 'cal_first_day'); $first_day = $first_day ? $first_day : 0; $htpl = get_markup_template('event_head.tpl'); \App::$page['htmlhead'] .= replace_macros($htpl, array('$baseurl' => z_root(), '$module_url' => '/cal/' . $channel['channel_address'], '$modparams' => 2, '$lang' => \App::$language, '$first_day' => $first_day)); $o = ''; $tabs = profile_tabs($a, True, $channel['channel_address']); $mode = 'view'; $y = 0; $m = 0; $ignored = x($_REQUEST, 'ignored') ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : ''; // logger('args: ' . print_r(\App::$argv,true)); if (argc() > 3 && intval(argv(2)) && intval(argv(3))) { $mode = 'view'; $y = intval(argv(2)); $m = intval(argv(3)); } if (argc() <= 3) { $mode = 'view'; $event_id = argv(2); } if ($mode == 'view') { /* edit/create form */ if ($event_id) { $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", dbesc($event_id), intval($channel['channel_id'])); if (count($r)) { $orig_event = $r[0]; } } // Passed parameters overrides anything found in the DB if (!x($orig_event)) { $orig_event = array(); } $tz = date_default_timezone_get(); if (x($orig_event)) { $tz = $orig_event['adjust'] ? date_default_timezone_get() : 'UTC'; } $syear = datetime_convert('UTC', $tz, $sdt, 'Y'); $smonth = datetime_convert('UTC', $tz, $sdt, 'm'); $sday = datetime_convert('UTC', $tz, $sdt, 'd'); $shour = datetime_convert('UTC', $tz, $sdt, 'H'); $sminute = datetime_convert('UTC', $tz, $sdt, 'i'); $stext = datetime_convert('UTC', $tz, $sdt); $stext = substr($stext, 0, 14) . "00:00"; $fyear = datetime_convert('UTC', $tz, $fdt, 'Y'); $fmonth = datetime_convert('UTC', $tz, $fdt, 'm'); $fday = datetime_convert('UTC', $tz, $fdt, 'd'); $fhour = datetime_convert('UTC', $tz, $fdt, 'H'); $fminute = datetime_convert('UTC', $tz, $fdt, 'i'); $ftext = datetime_convert('UTC', $tz, $fdt); $ftext = substr($ftext, 0, 14) . "00:00"; $type = x($orig_event) ? $orig_event['etype'] : 'event'; $f = get_config('system', 'event_input_format'); if (!$f) { $f = 'ymd'; } $catsenabled = feature_enabled($channel['channel_id'], 'categories'); $show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts'); if (!$show_bd) { $sql_extra .= " and event.etype != 'birthday' "; } $category = ''; $thisyear = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y'); $thismonth = datetime_convert('UTC', date_default_timezone_get(), 'now', 'm'); if (!$y) { $y = intval($thisyear); } if (!$m) { $m = intval($thismonth); } // Put some limits on dates. The PHP date functions don't seem to do so well before 1900. // An upper limit was chosen to keep search engines from exploring links millions of years in the future. if ($y < 1901) { $y = 1900; } if ($y > 2099) { $y = 2100; } $nextyear = $y; $nextmonth = $m + 1; if ($nextmonth > 12) { $nextmonth = 1; $nextyear++; } $prevyear = $y; if ($m > 1) { $prevmonth = $m - 1; } else { $prevmonth = 12; $prevyear--; } $dim = get_dim($y, $m); $start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0); $finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59); if (argv(2) === 'json') { if (x($_GET, 'start')) { $start = $_GET['start']; } if (x($_GET, 'end')) { $finish = $_GET['end']; } } $start = datetime_convert('UTC', 'UTC', $start); $finish = datetime_convert('UTC', 'UTC', $finish); $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); if (x($_GET, 'id')) { $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan\n\t from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d {$sql_extra} limit 1", intval($channel['channel_id']), intval($_GET['id'])); } else { // fixed an issue with "nofinish" events not showing up in the calendar. // There's still an issue if the finish date crosses the end of month. // Noting this for now - it will need to be fixed here and in Friendica. // Ultimately the finish date shouldn't be involved in the query. $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan\n\t from event left join item on event_hash = resource_id \n\t\t\t\t\twhere resource_type = 'event' and event.uid = %d {$ignored} \n\t\t\t\t\tAND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' ) \n\t\t\t\t\tOR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) {$sql_extra} ", intval($channel['channel_id']), dbesc($start), dbesc($finish), dbesc($adjust_start), dbesc($adjust_finish)); } $links = array(); if ($r) { xchan_query($r); $r = fetch_post_tags($r, true); $r = sort_by_date($r); } if ($r) { foreach ($r as $rr) { $j = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j'); if (!x($links, $j)) { $links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j; } } } $events = array(); $last_date = ''; $fmt = t('l, F j'); if ($r) { foreach ($r as $rr) { $j = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j'); $d = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], $fmt) : datetime_convert('UTC', 'UTC', $rr['dtstart'], $fmt); $d = day_translate($d); $start = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'); if ($rr['nofinish']) { $end = null; } else { $end = $rr['adjust'] ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'); } $is_first = $d !== $last_date; $last_date = $d; $edit = false; $drop = false; $title = strip_tags(html_entity_decode(bbcode($rr['summary']), ENT_QUOTES, 'UTF-8')); if (!$title) { list($title, $_trash) = explode("<br", bbcode($rr['desc']), 2); $title = strip_tags(html_entity_decode($title, ENT_QUOTES, 'UTF-8')); } $html = format_event_html($rr); $rr['desc'] = bbcode($rr['desc']); $rr['location'] = bbcode($rr['location']); $events[] = array('id' => $rr['id'], 'hash' => $rr['event_hash'], 'start' => $start, 'end' => $end, 'drop' => $drop, 'allDay' => false, 'title' => $title, 'j' => $j, 'd' => $d, 'edit' => $edit, 'is_first' => $is_first, 'item' => $rr, 'html' => $html, 'plink' => array($rr['plink'], t('Link to Source'), '', '')); } } if (argv(2) === 'json') { echo json_encode($events); killme(); } // links: array('href', 'text', 'extra css classes', 'title') if (x($_GET, 'id')) { $tpl = get_markup_template("event_cal.tpl"); } else { $tpl = get_markup_template("events_cal-js.tpl"); } $nick = $channel['channel_address']; $o = replace_macros($tpl, array('$baseurl' => z_root(), '$new_event' => array(z_root() . '/cal', $event_id ? t('Edit Event') : t('Create Event'), '', ''), '$previus' => array(z_root() . "/cal/{$nick}/{$prevyear}/{$prevmonth}", t('Previous'), '', ''), '$next' => array(z_root() . "/cal/{$nick}/{$nextyear}/{$nextmonth}", t('Next'), '', ''), '$export' => array(z_root() . "/cal/{$nick}/{$y}/{$m}/export", t('Export'), '', ''), '$calendar' => cal($y, $m, $links, ' eventcal'), '$events' => $events, '$upload' => t('Import'), '$submit' => t('Submit'), '$prev' => t('Previous'), '$next' => t('Next'), '$today' => t('Today'), '$form' => $form, '$expandform' => x($_GET, 'expandform') ? true : false, '$tabs' => $tabs)); if (x($_GET, 'id')) { echo $o; killme(); } return $o; } }
function delAssoc($handle) { logger('delAssoc'); $channel = channelx_by_nick(basename($handle)); if ($channel) { return del_pconfig($channel['channel_id'], 'openid', 'associate'); } }
function oep_profile_reply($args) { require_once 'include/identity.php'; require_once 'include/Contact.php'; $url = $args['url']; if (preg_match('#//(.*?)/(.*?)/(.*?)(/|\\?|&|$)#', $url, $matches)) { $chn = $matches[3]; } if (!$chn) { return; } $c = channelx_by_nick($chn); if (!$c) { return; } $maxwidth = intval($args['maxwidth']); $maxheight = intval($args['maxheight']); $width = 800; $height = 375; if ($maxwidth) { $width = $maxwidth; $height = 375 / 800 * $width; } if ($maxheight) { if ($maxheight < $height) { $width = 800 / 375 * $maxheight; $height = $maxheight; } } $ret = array(); $ret['type'] = 'rich'; $ret['width'] = intval($width); $ret['height'] = intval($height); $ret['html'] = get_zcard_embed($c, get_observer_hash(), array('width' => $width, 'height' => $height)); return $ret; }
function pubsubhubbub_init(&$a) { // PuSH subscription must be considered "public" so just block it // if public access isn't enabled. if (get_config('system', 'block_public')) { http_status_exit(403); } // Subscription request from subscriber // https://pubsubhubbub.googlecode.com/git/pubsubhubbub-core-0.4.html#anchor4 // Example from GNU Social: // [hub_mode] => subscribe // [hub_callback] => http://status.local/main/push/callback/1 // [hub_verify] => sync // [hub_verify_token] => af11... // [hub_secret] => af11... // [hub_topic] => http://friendica.local/dfrn_poll/sazius if ($_SERVER['REQUEST_METHOD'] === 'POST') { $hub_mode = push_post_var('hub_mode'); $hub_callback = push_post_var('hub_callback'); $hub_verify = push_post_var('hub_verify'); $hub_verify_token = push_post_var('hub_verify_token'); $hub_secret = push_post_var('hub_secret'); $hub_topic = push_post_var('hub_topic'); // check for valid hub_mode if ($hub_mode === 'subscribe') { $subscribe = 1; } else { if ($hub_mode === 'unsubscribe') { $subscribe = 0; } else { logger("pubsubhubbub: invalid hub_mode={$hub_mode}, ignoring."); http_status_exit(404); } } logger("pubsubhubbub: {$hub_mode} request from " . $_SERVER['REMOTE_ADDR']); // get the nick name from the topic, a bit hacky but needed $nick = substr(strrchr($hub_topic, "/"), 1); if (!$nick) { logger('pubsubhubbub: bad hub_topic=$hub_topic, ignoring.'); http_status_exit(404); } // fetch user from database given the nickname $owner = channelx_by_nick($nick); if (!$owner) { logger('pubsubhubbub: local account not found: ' . $nick); http_status_exit(404); } if (!perm_is_allowed($owner['channel_id'], '', 'view_stream')) { logger('pubsubhubbub: local channel ' . $nick . 'has chosen to hide wall, ignoring.'); http_status_exit(403); } // sanity check that topic URLs are the same if (!link_compare($hub_topic, z_root() . '/feed/' . $nick)) { logger('pubsubhubbub: not a valid hub topic ' . $hub_topic); http_status_exit(404); } // do subscriber verification according to the PuSH protocol $hub_challenge = random_string(40); $params = 'hub.mode=' . ($subscribe == 1 ? 'subscribe' : 'unsubscribe') . '&hub.topic=' . urlencode($hub_topic) . '&hub.challenge=' . $hub_challenge . '&hub.lease_seconds=604800' . '&hub.verify_token=' . $hub_verify_token; // lease time is hard coded to one week (in seconds) // we don't actually enforce the lease time because GNU // Social/StatusNet doesn't honour it (yet) $x = z_fetch_url($hub_callback . "?" . $params); if (!$x['success']) { logger("pubsubhubbub: subscriber verification at {$hub_callback} " . "returned {$ret}, ignoring."); http_status_exit(404); } // check that the correct hub_challenge code was echoed back if (trim($x['body']) !== $hub_challenge) { logger("pubsubhubbub: subscriber did not echo back " . "hub.challenge, ignoring."); logger("\"{$hub_challenge}\" != \"" . trim($x['body']) . "\""); http_status_exit(404); } // fetch the old subscription if it exists $orig = q("SELECT * FROM `push_subscriber` WHERE `callback_url` = '%s'", dbesc($hub_callback)); // delete old subscription if it exists q("DELETE FROM push_subscriber WHERE callback_url = '%s' and topic = '%s'", dbesc($hub_callback), dbesc($hub_topic)); if ($subscribe) { $last_update = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s'); // if we are just updating an old subscription, keep the // old values for last_update if ($orig) { $last_update = $orig[0]['last_update']; } // subscribe means adding the row to the table q("INSERT INTO push_subscriber ( callback_url, topic, last_update, secret) values ('%s', '%s', '%s', '%s') ", dbesc($hub_callback), dbesc($hub_topic), dbesc($last_update), dbesc($hub_secret)); logger("pubsubhubbub: successfully subscribed [{$hub_callback}]."); } else { logger("pubsubhubbub: successfully unsubscribed [{$hub_callback}]."); // we do nothing here, since the row was already deleted } http_status_exit(202); } killme(); }
/** * @brief Verify login credentials. * * If system.authlog is set a log entry will be added for failed login * attempts. * * @param string $login * The login to verify (channel address, account email or guest login token). * @param string $pass * The provided password to verify. * @return array|null * Returns account record on success, null on failure. * The return array is dependent on the login mechanism. * $ret['account'] will be set if either an email or channel address validation was successful (local login). * $ret['channel'] will be set if a channel address validation was successful. * $ret['xchan'] will be set if a guest access token validation was successful. * Keys will exist for invalid return arrays but will be set to null. * This function does not perform a login. It merely validates systems passwords and tokens. * */ function account_verify_password($login, $pass) { $ret = ['account' => null, 'channel' => null, 'xchan' => null]; $email_verify = get_config('system', 'verify_email'); $register_policy = get_config('system', 'register_policy'); if (!$login) { return null; } $account = null; $channel = null; $xchan = null; if (!strpos($login, '@')) { $channel = channelx_by_nick($login); if (!$channel) { $x = q("select * from atoken where atoken_name = '%s' and atoken_token = '%s' limit 1", dbesc($login), dbesc($pass)); if ($x) { $ret['xchan'] = atoken_xchan($x[0]); atoken_create_xchan($ret['xchan']); return $ret; } } } if ($channel) { $where = " where account_id = " . intval($channel['channel_account_id']) . " "; } else { $where = " where account_email = '" . dbesc($login) . "' "; } $a = q("select * from account {$where}"); if (!$a) { return null; } $account = $a[0]; // Currently we only verify email address if there is an open registration policy. // This isn't because of any policy - it's because the workflow gets too complicated if // you have to verify the email and then go through the account approval workflow before // letting them login. if ($email_verify && $register_policy == REGISTER_OPEN && $account['account_flags'] & ACCOUNT_UNVERIFIED) { logger('email verification required for ' . $login); return null; } if ($account['account_flags'] == ACCOUNT_OK && hash('whirlpool', $account['account_salt'] . $pass) === $account['account_password']) { logger('password verified for ' . $login); $ret['account'] = $account; if ($channel) { $ret['channel'] = $channel; } return $ret; } $error = 'password failed for ' . $login; logger($error); if ($account['account_flags'] & ACCOUNT_UNVERIFIED) { logger('Account is unverified. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_BLOCKED) { logger('Account is blocked. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_EXPIRED) { logger('Account is expired. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_REMOVED) { logger('Account is removed. account_flags = ' . $account['account_flags']); } if ($account['account_flags'] & ACCOUNT_PENDING) { logger('Account is pending. account_flags = ' . $account['account_flags']); } log_failed_login($error); return null; }
function salmon_post(&$a) { $sys_disabled = true; if (!get_config('system', 'disable_discover_tab')) { $sys_disabled = get_config('system', 'disable_diaspora_discover_tab'); } $sys = $sys_disabled ? null : get_sys_channel(); if (App::$data['salmon_test']) { $xml = file_get_contents('test.xml'); App::$argv[1] = 'gnusoc'; } else { $xml = file_get_contents('php://input'); } logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA); $nick = argc() > 1 ? trim(argv(1)) : ''; // $mentions = ((App::$argc > 2 && App::$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. logger('sig: ' . $base->sig); $signature = base64url_decode($base->sig); logger('sig: ' . $base->sig . ' decoded length: ' . strlen($signature)); // 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, false) . '.' . base64url_encode($encoding, false) . '.' . base64url_encode($alg, false); $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, '<feed')) { $data = str_replace('<entry ', '<feed xmlns="http://www.w3.org/2005/Atom"><entry ', $data); $data .= '</feed>'; } $datarray = process_salmon_feed($data, $importer); $author_link = $datarray['author']['author_link']; $item = $datarray['item']; if (!$author_link) { logger('mod-salmon: Could not retrieve author URI.'); http_status_exit(400); } $r = q("select xchan_pubkey from xchan where xchan_guid = '%s' limit 1", dbesc($author_link)); if ($r) { $pubkey = $r[0]['xchan_pubkey']; } else { // Once we have the author URI, go to the web and try to find their public key logger('mod-salmon: Fetching key for ' . $author_link); $pubkey = get_salmon_key($author_link, $keyhash); if (!$pubkey) { logger('mod-salmon: Could not retrieve author key.'); http_status_exit(400); } logger('mod-salmon: key details: ' . print_r($pubkey, true), LOGGER_DEBUG); } $pubkey = rtrim($pubkey); // We should have everything we need now. Let's see if it verifies. $verify = rsa_verify($signed_data, $signature, $pubkey); if (!$verify) { logger('mod-salmon: message did not verify using protocol. Trying padding hack.'); $verify = rsa_verify($compliant_format, $signature, $pubkey); } if (!$verify) { logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.'); $verify = rsa_verify($stnet_signed_data, $signature, $pubkey); } if (!$verify) { logger('mod-salmon: Message did not verify. Discarding.'); http_status_exit(400); } logger('mod-salmon: Message verified.'); /* lookup the author */ if (!$datarray['author']['author_link']) { logger('unable to probe - no author identifier'); http_status_exit(400); } $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($datarray['author']['author_link'])); if (!$r) { if (discover_by_webbie($datarray['author']['author_link'])) { $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($datarray['author']['author_link'])); if (!$r) { logger('discovery failed'); http_status_exit(400); } } } $xchan = $r[0]; /* * * If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff. * */ // First check for and process follow activity if (activity_match($item['verb'], ACTIVITY_FOLLOW) && $item['obj_type'] === ACTIVITY_OBJ_PERSON) { $cb = array('item' => $item, 'channel' => $importer, 'xchan' => $xchan, 'author' => $datarray['author'], 'caught' => false); call_hooks('follow_from_feed', $cb); if ($cb['caught']) { http_status_exit(200); } } $m = parse_url($xchan['xchan_url']); if ($m) { $host = $m['scheme'] . '://' . $m['host']; q("update site set site_dead = 0, site_update = '%s' where site_type = %d and site_url = '%s'", dbesc(datetime_convert()), intval(SITE_TYPE_NOTZOT), dbesc($url)); if (!check_siteallowed($host)) { logger('blacklisted site: ' . $host); http_status_exit(403, 'permission denied.'); } } $importer_arr = array($importer); if (!$sys_disabled) { $sys['system'] = true; $importer_arr[] = $sys; } unset($datarray['author']); // we will only set and return the status code for operations // on an importer channel and not for the sys channel $status = 200; foreach ($importer_arr as $importer) { if (!$importer['system']) { $allowed = get_pconfig($importer['channel_id'], 'system', 'gnusoc_allowed'); if (!intval($allowed)) { logger('mod-salmon: disallowed for channel ' . $importer['channel_name']); $status = 202; continue; } } // Otherwise check general permissions if (!perm_is_allowed($importer['channel_id'], $xchan['xchan_hash'], 'send_stream') && !$importer['system']) { // check for and process ostatus autofriend // ... fixme // otherwise logger('mod-salmon: Ignoring this author.'); $status = 202; continue; } $parent_item = null; if ($item['parent_mid']) { $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($importer['channel_id'])); if (!$r) { logger('mod-salmon: parent item not found.'); if (!$importer['system']) { $status = 202; } continue; } $parent_item = $r[0]; } if (!$item['author_xchan']) { $item['author_xchan'] = $xchan['xchan_hash']; } $item['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($item['mid']), intval($importer['channel_id'])); // Update content if 'updated' changes // currently a no-op @fixme if ($r) { if (x($item, 'edited') !== false && datetime_convert('UTC', 'UTC', $item['edited']) !== $r[0]['edited']) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $item['edited']) > $r[0]['edited']) { update_feed_item($importer['channel_id'], $item); } } if (!$importer['system']) { $status = 200; } continue; } if (!$item['parent_mid']) { $item['parent_mid'] = $item['mid']; } $item['aid'] = $importer['channel_account_id']; $item['uid'] = $importer['channel_id']; logger('consume_feed: ' . print_r($item, true), LOGGER_DATA); $xx = item_store($item); $r = $xx['item_id']; if (!$importer['system']) { $status = 200; } continue; } http_status_exit($status); }