Beispiel #1
0
function post_post(&$a)
{
    $bulk_delivery = false;
    if ($a->argc == 1) {
        $bulk_delivery = true;
    } else {
        $nickname = $a->argv[2];
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' \n\t\t\t\tAND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nickname));
        if (!count($r)) {
            http_status_exit(500);
        }
        $importer = $r[0];
    }
    $xml = file_get_contents('php://input');
    logger('mod-post: new zot: ' . $xml, LOGGER_DATA);
    if (!$xml) {
        http_status_exit(500);
    }
    $msg = zot_decode($importer, $xml);
    logger('mod-post: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
    if (!is_array($msg)) {
        http_status_exit(500);
    }
    $ret = 0;
    $ret = zot_incoming($bulk_delivery, $importer, $msg);
    http_status_exit($ret ? $ret : 200);
    // NOTREACHED
}
Beispiel #2
0
function _well_known_init(&$a)
{
    if (argc() > 1) {
        $arr = array('server' => $_SERVER, 'request' => $_REQUEST);
        call_hooks('well_known', $arr);
        switch (argv(1)) {
            case 'zot-info':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'zfinger';
                require_once 'mod/zfinger.php';
                zfinger_init($a);
                break;
            case 'webfinger':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'wfinger';
                require_once 'mod/wfinger.php';
                wfinger_init($a);
                break;
            case 'host-meta':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'hostxrd';
                require_once 'mod/hostxrd.php';
                hostxrd_init($a);
                break;
            default:
                break;
        }
    }
    http_status_exit(404);
}
Beispiel #3
0
 function init()
 {
     if (argc() != 3 || !in_array(argv(1), ['post', 'status_message', 'reshare'])) {
         http_status_exit(404, 'Not found');
     }
     $guid = argv(2);
     // Fetch the item
     $item = q("SELECT * from item where mid = '%s' and item_private = 0 and mid = parent_mid limit 1", dbesc($guid));
     if (!$item) {
         http_status_exit(404, 'Not found');
     }
     xchan_query($item);
     $item = fetch_post_tags($item, true);
     $channel = channelx_by_hash($item[0]['author_xchan']);
     if (!$channel) {
         $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item[0]['author_xchan']));
         if ($r) {
             $url = $r[0]['xchan_url'];
             if (strpos($url, z_root()) === false) {
                 $m = parse_url($url);
                 goaway($m['scheme'] . '://' . $m['host'] . ($m['port'] ? ':' . $m['port'] : '') . '/fetch/' . argv(1) . '/' . argv(2));
             }
         }
         http_status_exit(404, 'Not found');
     }
     $status = diaspora_build_status($item[0], $channel);
     header("Content-type: application/magic-envelope+xml; charset=utf-8");
     echo diaspora_magic_env($channel, $status);
     killme();
 }
Beispiel #4
0
function p_init(&$a)
{
    if (argc() < 2) {
        http_status_exit(401);
    }
    $mid = str_replace('.xml', '', argv(1));
    $r = q("select * from item where mid = '%s' and item_wall = 1 and item_private = 0 limit 1", dbesc($mid));
    if (!$r || !perm_is_allowed($r[0]['uid'], '', 'view_stream')) {
        http_status_exit(404);
    }
    $c = q("select * from channel where channel_id = %d limit 1", intval($r[0]['uid']));
    if (!$c) {
        http_status_exit(404);
    }
    $myaddr = $c[0]['channel_address'] . '@' . App::get_hostname();
    $item = $r[0];
    $title = $item['title'];
    $body = bb2diaspora_itembody($item);
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    $tpl = get_markup_template('diaspora_post.tpl', 'addon/diaspora');
    $msg = replace_macros($tpl, array('$body' => xmlify($body), '$guid' => $item['mid'], '$handle' => xmlify($myaddr), '$public' => 'true', '$created' => $created, '$provider' => $item['app'] ? $item['app'] : t('$projectname')));
    header('Content-type: text/xml');
    echo $msg;
    killme();
}
Beispiel #5
0
function _well_known_init(&$a)
{
    if (argc() > 1) {
        $arr = array('server' => $_SERVER, 'request' => $_REQUEST);
        call_hooks('well_known', $arr);
        if (!check_siteallowed($_SERVER['REMOTE_ADDR'])) {
            logger('well_known: site not allowed. ' . $_SERVER['REMOTE_ADDR']);
            killme();
        }
        // from php.net re: REMOTE_HOST:
        //     Note: Your web server must be configured to create this variable. For example in Apache
        // you'll need HostnameLookups On inside httpd.conf for it to exist. See also gethostbyaddr().
        if (get_config('system', 'siteallowed_remote_host') && !check_siteallowed($_SERVER['REMOTE_HOST'])) {
            logger('well_known: site not allowed. ' . $_SERVER['REMOTE_HOST']);
            killme();
        }
        switch (argv(1)) {
            case 'zot-info':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'zfinger';
                require_once 'mod/zfinger.php';
                zfinger_init($a);
                break;
            case 'webfinger':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'wfinger';
                require_once 'mod/wfinger.php';
                wfinger_init($a);
                break;
            case 'host-meta':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'hostxrd';
                require_once 'mod/hostxrd.php';
                hostxrd_init($a);
                break;
            default:
                // look in $WEBROOT/well_known for the requested file in case it is
                // something a site requires and for which we do not have a module
                // @fixme - we may need to determine the content-type and stick it in the header
                // for now this can be done with a php script masquerading as the requested file
                $wk_file = str_replace('.well-known', 'well_known', $a->cmd);
                if (file_exists($wk_file)) {
                    echo file_get_contents($wk_file);
                    killme();
                } elseif (file_exists($wk_file . '.php')) {
                    require_once $wk_file . '.php';
                }
                break;
        }
    }
    http_status_exit(404);
}
Beispiel #6
0
function _well_known_init(&$a)
{
    if ($a->argc > 1) {
        switch ($a->argv[1]) {
            case "host-meta":
                hostxrd_init($a);
                break;
        }
    }
    http_status_exit(404);
    killme();
}
Beispiel #7
0
function _well_known_init(&$a)
{
    if (argc() > 1) {
        $arr = array('server' => $_SERVER, 'request' => $_REQUEST);
        call_hooks('well_known', $arr);
        if (!check_siteallowed($_SERVER['REMOTE_ADDR'])) {
            logger('well_known: site not allowed. ' . $_SERVER['REMOTE_ADDR']);
            killme();
        }
        // from php.net re: REMOTE_HOST:
        //     Note: Your web server must be configured to create this variable. For example in Apache
        // you'll need HostnameLookups On inside httpd.conf for it to exist. See also gethostbyaddr().
        if (get_config('system', 'siteallowed_remote_host') && !check_siteallowed($_SERVER['REMOTE_HOST'])) {
            logger('well_known: site not allowed. ' . $_SERVER['REMOTE_HOST']);
            killme();
        }
        switch (argv(1)) {
            case 'zot-info':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'zfinger';
                require_once 'mod/zfinger.php';
                zfinger_init($a);
                break;
            case 'webfinger':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'wfinger';
                require_once 'mod/wfinger.php';
                wfinger_init($a);
                break;
            case 'host-meta':
                $a->argc -= 1;
                array_shift($a->argv);
                $a->argv[0] = 'hostxrd';
                require_once 'mod/hostxrd.php';
                hostxrd_init($a);
                break;
            default:
                if (file_exists($a->cmd)) {
                    echo file_get_contents($a->cmd);
                    killme();
                } elseif (file_exists($a->cmd . '.php')) {
                    require_once $a->cmd . '.php';
                }
                break;
        }
    }
    http_status_exit(404);
}
Beispiel #8
0
 function init()
 {
     logger('oep: ' . print_r($_REQUEST, true), LOGGER_DEBUG, LOG_INFO);
     $html = argc() > 1 && argv(1) === 'html' ? true : false;
     if ($_REQUEST['url']) {
         $_REQUEST['url'] = strip_zids($_REQUEST['url']);
         $url = $_REQUEST['url'];
     }
     if (!$url) {
         http_status_exit(404, 'Not found');
     }
     $maxwidth = $_REQUEST['maxwidth'];
     $maxheight = $_REQUEST['maxheight'];
     $format = $_REQUEST['format'];
     if ($format && $format !== 'json') {
         http_status_exit(501, 'Not implemented');
     }
     if (fnmatch('*/photos/*/album/*', $url)) {
         $arr = $this->oep_album_reply($_REQUEST);
     } elseif (fnmatch('*/photos/*/image/*', $url)) {
         $arr = $this->oep_photo_reply($_REQUEST);
     } elseif (fnmatch('*/photos*', $url)) {
         $arr = $this->oep_phototop_reply($_REQUEST);
     } elseif (fnmatch('*/display/*', $url)) {
         $arr = $this->oep_display_reply($_REQUEST);
     } elseif (fnmatch('*/channel/*mid=*', $url)) {
         $arr = $this->oep_mid_reply($_REQUEST);
     } elseif (fnmatch('*/channel*', $url)) {
         $arr = $this->oep_profile_reply($_REQUEST);
     } elseif (fnmatch('*/profile/*', $url)) {
         $arr = $this->oep_profile_reply($_REQUEST);
     }
     if ($arr) {
         if ($html) {
             if ($arr['type'] === 'rich') {
                 header('Content-Type: text/html');
                 echo $arr['html'];
             }
         } else {
             header('Content-Type: application/json+oembed');
             echo json_encode($arr);
         }
         killme();
     }
     http_status_exit(404, 'Not found');
 }
function receive_post(&$a)
{
    $public = false;
    logger('diaspora_receive: ' . print_r($a->argv, true), LOGGER_DEBUG);
    if (argc() == 2 && argv(1) === 'public') {
        $public = true;
    } else {
        if (argc() != 3 || argv(1) !== 'users') {
            http_status_exit(500);
        }
        $guid = argv(2);
        $hn = str_replace('.', '', $a->get_hostname());
        if (($x = strpos($guid, $hn)) > 0) {
            $guid = substr($guid, 0, $x);
        }
        // Diaspora sites *may* provide a truncated guid.
        $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_guid like '%s' AND channel_removed = 0 LIMIT 1", dbesc($guid . '%'));
        if (!$r) {
            http_status_exit(500);
        }
        $importer = $r[0];
    }
    // It is an application/x-www-form-urlencoded that has been urlencoded twice.
    logger('mod-diaspora: receiving post', LOGGER_DEBUG);
    $xml = urldecode($_POST['xml']);
    logger('mod-diaspora: new salmon ' . $xml, LOGGER_DATA);
    if (!$xml) {
        http_status_exit(500);
    }
    logger('mod-diaspora: message is okay', LOGGER_DEBUG);
    $msg = diaspora_decode($importer, $xml);
    logger('mod-diaspora: decoded', LOGGER_DEBUG);
    logger('mod-diaspora: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
    if (!is_array($msg)) {
        http_status_exit(500);
    }
    logger('mod-diaspora: dispatching', LOGGER_DEBUG);
    $ret = 0;
    if ($public) {
        diaspora_dispatch_public($msg);
    } else {
        $ret = diaspora_dispatch($importer, $msg);
    }
    http_status_exit($ret ? $ret : 200);
    // NOTREACHED
}
Beispiel #10
0
function receive_post(&$a)
{
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('mod-diaspora: disabled');
        http_status_exit(500);
    }
    $public = false;
    if (argc() == 2 && argv(1) === 'public') {
        $public = true;
    } else {
        if (argc() != 3 || argv(1) !== 'users') {
            http_status_exit(500);
        }
        $guid = argv(2);
        // Diaspora sites *may* provide a truncated guid.
        $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_guid like '%s' AND NOT (channel_pageflags & %d )>0 LIMIT 1", dbesc($guid . '%'), intval(PAGE_REMOVED));
        if (!$r) {
            http_status_exit(500);
        }
        $importer = $r[0];
    }
    // It is an application/x-www-form-urlencoded that has been urlencoded twice.
    logger('mod-diaspora: receiving post', LOGGER_DEBUG);
    $xml = urldecode($_POST['xml']);
    logger('mod-diaspora: new salmon ' . $xml, LOGGER_DATA);
    if (!$xml) {
        http_status_exit(500);
    }
    logger('mod-diaspora: message is okay', LOGGER_DEBUG);
    $msg = diaspora_decode($importer, $xml);
    logger('mod-diaspora: decoded', LOGGER_DEBUG);
    logger('mod-diaspora: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
    if (!is_array($msg)) {
        http_status_exit(500);
    }
    logger('mod-diaspora: dispatching', LOGGER_DEBUG);
    $ret = 0;
    if ($public) {
        diaspora_dispatch_public($msg);
    } else {
        $ret = diaspora_dispatch($importer, $msg);
    }
    http_status_exit($ret ? $ret : 200);
    // NOTREACHED
}
Beispiel #11
0
function receive_post(&$a)
{
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('mod-diaspora: disabled');
        http_status_exit(500);
    }
    $public = false;
    if ($a->argc == 2 && $a->argv[1] === 'public') {
        $public = true;
    } else {
        if ($a->argc != 3 || $a->argv[1] !== 'users') {
            http_status_exit(500);
        }
        $guid = $a->argv[2];
        $r = q("SELECT * FROM `user` WHERE `guid` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($guid));
        if (!count($r)) {
            http_status_exit(500);
        }
        $importer = $r[0];
    }
    // It is an application/x-www-form-urlencoded
    logger('mod-diaspora: receiving post', LOGGER_DEBUG);
    $xml = urldecode($_POST['xml']);
    logger('mod-diaspora: new salmon ' . $xml, LOGGER_DATA);
    if (!$xml) {
        http_status_exit(500);
    }
    logger('mod-diaspora: message is okay', LOGGER_DEBUG);
    $msg = diaspora_decode($importer, $xml);
    logger('mod-diaspora: decoded', LOGGER_DEBUG);
    logger('mod-diaspora: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
    if (!is_array($msg)) {
        http_status_exit(500);
    }
    logger('mod-diaspora: dispatching', LOGGER_DEBUG);
    $ret = 0;
    if ($public) {
        diaspora_dispatch_public($msg);
    } else {
        $ret = diaspora_dispatch($importer, $msg);
    }
    http_status_exit($ret ? $ret : 200);
    // NOTREACHED
}
Beispiel #12
0
function _well_known_init(&$a)
{
    if ($a->argc > 1) {
        switch ($a->argv[1]) {
            case "host-meta":
                hostxrd_init($a);
                break;
            case "x-social-relay":
                wk_social_relay($a);
                break;
            case "nodeinfo":
                nodeinfo_wellknown($a);
                break;
        }
    }
    http_status_exit(404);
    killme();
}
Beispiel #13
0
function statistics_json_init(&$a)
{
    if (!get_config("system", "nodeinfo")) {
        http_status_exit(404);
        killme();
    }
    $statistics = array("name" => $a->config["sitename"], "network" => FRIENDICA_PLATFORM, "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION, "registrations_open" => $a->config['register_policy'] != 0, "total_users" => get_config('nodeinfo', 'total_users'), "active_users_halfyear" => get_config('nodeinfo', 'active_users_halfyear'), "active_users_monthly" => get_config('nodeinfo', 'active_users_monthly'), "local_posts" => get_config('nodeinfo', 'local_posts'));
    $statistics["services"] = array();
    $statistics["services"]["appnet"] = plugin_enabled("appnet");
    $statistics["services"]["blogger"] = plugin_enabled("blogger");
    $statistics["services"]["buffer"] = plugin_enabled("buffer");
    $statistics["services"]["dreamwidth"] = plugin_enabled("dwpost");
    $statistics["services"]["facebook"] = plugin_enabled("fbpost");
    $statistics["services"]["gnusocial"] = plugin_enabled("statusnet");
    $statistics["services"]["googleplus"] = plugin_enabled("gpluspost");
    $statistics["services"]["libertree"] = plugin_enabled("libertree");
    $statistics["services"]["livejournal"] = plugin_enabled("ljpost");
    $statistics["services"]["pumpio"] = plugin_enabled("pumpio");
    $statistics["services"]["twitter"] = plugin_enabled("twitter");
    $statistics["services"]["tumblr"] = plugin_enabled("tumblr");
    $statistics["services"]["wordpress"] = plugin_enabled("wppost");
    $statistics["appnet"] = $statistics["services"]["appnet"];
    $statistics["blogger"] = $statistics["services"]["blogger"];
    $statistics["buffer"] = $statistics["services"]["buffer"];
    $statistics["dreamwidth"] = $statistics["services"]["dreamwidth"];
    $statistics["facebook"] = $statistics["services"]["facebook"];
    $statistics["gnusocial"] = $statistics["services"]["gnusocial"];
    $statistics["googleplus"] = $statistics["services"]["googleplus"];
    $statistics["libertree"] = $statistics["services"]["libertree"];
    $statistics["livejournal"] = $statistics["services"]["livejournal"];
    $statistics["pumpio"] = $statistics["services"]["pumpio"];
    $statistics["twitter"] = $statistics["services"]["twitter"];
    $statistics["tumblr"] = $statistics["services"]["tumblr"];
    $statistics["wordpress"] = $statistics["services"]["wordpress"];
    header("Content-Type: application/json");
    echo json_encode($statistics, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    logger("statistics_init: printed " . print_r($statistics, true), LOGGER_DATA);
    killme();
}
Beispiel #14
0
function poco($a, $extended = false)
{
    $system_mode = false;
    if (observer_prohibited()) {
        logger('mod_poco: block_public');
        http_status_exit(401);
    }
    $observer = App::get_observer();
    if (argc() > 1) {
        $user = notags(trim(argv(1)));
    }
    if (!x($user)) {
        $c = q("select * from pconfig where cat = 'system' and k = 'suggestme' and v = '1'");
        if (!$c) {
            logger('mod_poco: system mode. No candidates.', LOGGER_DEBUG);
            http_status_exit(404);
        }
        $system_mode = true;
    }
    $format = $_REQUEST['format'] ? $_REQUEST['format'] : 'json';
    $justme = false;
    if (argc() > 2 && argv(2) === '@me') {
        $justme = true;
    }
    if (argc() > 3) {
        if (argv(3) === '@all') {
            $justme = false;
        } elseif (argv(3) === '@self') {
            $justme = true;
        }
    }
    if (argc() > 4 && intval(argv(4)) && $justme == false) {
        $cid = intval(argv(4));
    }
    if (!$system_mode) {
        $r = q("SELECT channel_id from channel where channel_address = '%s' limit 1", dbesc($user));
        if (!$r) {
            logger('mod_poco: user mode. Account not found. ' . $user);
            http_status_exit(404);
        }
        $channel_id = $r[0]['channel_id'];
        $ohash = $observer ? $observer['xchan_hash'] : '';
        if (!perm_is_allowed($channel_id, $ohash, 'view_contacts')) {
            logger('mod_poco: user mode. Permission denied for ' . $ohash . ' user: '******'system' and k = 'suggestme' and v = '1') ");
    } else {
        $r = q("SELECT count(*) as `total` from abook where abook_channel = %d \n\t\t\t{$sql_extra} ", intval($channel_id));
        $rooms = q("select * from menu_item where ( mitem_flags & " . intval(MENU_ITEM_CHATROOM) . " )>0 and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = '' and mitem_channel_id = %d", intval($channel_id));
    }
    if ($r) {
        $totalResults = intval($r[0]['total']);
    } else {
        $totalResults = 0;
    }
    $startIndex = intval($_GET['startIndex']);
    if (!$startIndex) {
        $startIndex = 0;
    }
    $itemsPerPage = x($_GET, 'count') && intval($_GET['count']) ? intval($_GET['count']) : $totalResults;
    if ($system_mode) {
        $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_self = 1 \n\t\t\tand abook_channel in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = '1') \n\t\t\tlimit %d offset %d ", intval($itemsPerPage), intval($startIndex));
    } else {
        $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d \n\t\t\t{$sql_extra} LIMIT %d OFFSET %d", intval($channel_id), intval($itemsPerPage), intval($startIndex));
    }
    $ret = array();
    if (x($_GET, 'sorted')) {
        $ret['sorted'] = 'false';
    }
    if (x($_GET, 'filtered')) {
        $ret['filtered'] = 'false';
    }
    if (x($_GET, 'updatedSince')) {
        $ret['updateSince'] = 'false';
    }
    $ret['startIndex'] = (string) $startIndex;
    $ret['itemsPerPage'] = (string) $itemsPerPage;
    $ret['totalResults'] = (string) $totalResults;
    if ($rooms) {
        $ret['chatrooms'] = array();
        foreach ($rooms as $room) {
            $ret['chatrooms'][] = array('url' => $room['mitem_link'], 'desc' => $room['mitem_desc']);
        }
    }
    $ret['entry'] = array();
    $fields_ret = array('id' => false, 'guid' => false, 'guid_sig' => false, 'hash' => false, 'displayName' => false, 'urls' => false, 'preferredUsername' => false, 'photos' => false, 'rating' => false);
    if (!x($_GET, 'fields') || $_GET['fields'] === '@all') {
        foreach ($fields_ret as $k => $v) {
            $fields_ret[$k] = true;
        }
    } else {
        $fields_req = explode(',', $_GET['fields']);
        foreach ($fields_req as $f) {
            $fields_ret[trim($f)] = true;
        }
    }
    if (is_array($r)) {
        if (count($r)) {
            foreach ($r as $rr) {
                $entry = array();
                if ($fields_ret['id']) {
                    $entry['id'] = $rr['abook_id'];
                }
                if ($fields_ret['guid']) {
                    $entry['guid'] = $rr['xchan_guid'];
                }
                if ($fields_ret['guid_sig']) {
                    $entry['guid_sig'] = $rr['xchan_guid_sig'];
                }
                if ($fields_ret['hash']) {
                    $entry['hash'] = $rr['xchan_hash'];
                }
                if ($fields_ret['displayName']) {
                    $entry['displayName'] = $rr['xchan_name'];
                }
                if ($fields_ret['urls']) {
                    $entry['urls'] = array(array('value' => $rr['xchan_url'], 'type' => 'profile'));
                    $network = $rr['xchan_network'];
                    if (strpos($network, 'friendica') !== false) {
                        $network = 'friendica';
                    }
                    if ($rr['xchan_addr']) {
                        $entry['urls'][] = array('value' => 'acct:' . $rr['xchan_addr'], 'type' => $network);
                    }
                }
                if ($fields_ret['preferredUsername']) {
                    $entry['preferredUsername'] = substr($rr['xchan_addr'], 0, strpos($rr['xchan_addr'], '@'));
                }
                if ($fields_ret['photos']) {
                    $entry['photos'] = array(array('value' => $rr['xchan_photo_l'], 'mimetype' => $rr['xchan_photo_mimetype'], 'type' => 'profile'));
                }
                $ret['entry'][] = $entry;
            }
        } else {
            $ret['entry'][] = array();
        }
    } else {
        http_status_exit(500);
    }
    if ($format === 'xml') {
        header('Content-type: text/xml');
        echo replace_macros(get_markup_template('poco_xml.tpl'), array_xmlify(array('$response' => $ret)));
        http_status_exit(500);
    }
    if ($format === 'json') {
        header('Content-type: application/json');
        echo json_encode($ret);
        killme();
    } else {
        http_status_exit(500);
    }
}
Beispiel #15
0
function salmon_post(&$a)
{
    $xml = file_get_contents('php://input');
    logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA);
    $nick = $a->argc > 1 ? notags(trim($a->argv[1])) : '';
    $mentions = $a->argc > 2 && $a->argv[2] === 'mention' ? true : false;
    $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nick));
    if (!count($r)) {
        http_status_exit(500);
    }
    $importer = $r[0];
    // 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);
    }
    // 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);
    $author = ostatus_salmon_author($data, $importer);
    $author_link = $author["author-link"];
    if (!$author_link) {
        logger('mod-salmon: Could not retrieve author URI.');
        http_status_exit(400);
    }
    // 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);
    $key = get_salmon_key($author_link, $keyhash);
    if (!$key) {
        logger('mod-salmon: Could not retrieve author key.');
        http_status_exit(400);
    }
    $key_info = explode('.', $key);
    $m = base64url_decode($key_info[1]);
    $e = base64url_decode($key_info[2]);
    logger('mod-salmon: key details: ' . print_r($key_info, true), LOGGER_DEBUG);
    $pubkey = metopem($m, $e);
    // We should have everything we need now. Let's see if it verifies.
    $verify = rsa_verify($compliant_format, $signature, $pubkey);
    if (!$verify) {
        logger('mod-salmon: message did not verify using protocol. Trying padding hack.');
        $verify = rsa_verify($signed_data, $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.');
    /*
     *
     * If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff.
     *
     */
    $r = q("SELECT * FROM `contact` WHERE `network` IN ('%s', '%s')\n\t\t\t\t\t\tAND (`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s')\n\t\t\t\t\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN), dbesc(normalise_link($author_link)), dbesc($author_link), dbesc(normalise_link($author_link)), intval($importer['uid']));
    if (!count($r)) {
        logger('mod-salmon: Author unknown to us.');
        if (get_pconfig($importer['uid'], 'system', 'ostatus_autofriend')) {
            $result = new_contact($importer['uid'], $author_link);
            if ($result['success']) {
                $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s') \n\t\t\t\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), dbesc($author_link), intval($importer['uid']));
            }
        }
    }
    // Have we ignored the person?
    // If so we can not accept this post.
    //if((count($r)) && (($r[0]['readonly']) || ($r[0]['rel'] == CONTACT_IS_FOLLOWER) || ($r[0]['blocked']))) {
    if (count($r) && $r[0]['blocked']) {
        logger('mod-salmon: Ignoring this author.');
        http_status_exit(202);
        // NOTREACHED
    }
    // Placeholder for hub discovery.
    $hub = '';
    $contact_rec = count($r) ? $r[0] : null;
    ostatus_import($data, $importer, $contact_rec, $hub);
    http_status_exit(200);
}
Beispiel #16
0
function nodeinfo_init(&$a)
{
    if (!get_config("system", "nodeinfo")) {
        http_status_exit(404);
        killme();
    }
    if ($a->argc != 2 or $a->argv[1] != "1.0") {
        http_status_exit(404);
        killme();
    }
    $smtp = (function_exists("imap_open") and !get_config("system", "imap_disabled") and !get_config("system", "dfrn_only"));
    $nodeinfo = array();
    $nodeinfo["version"] = "1.0";
    $nodeinfo["software"] = array("name" => "friendica", "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION);
    $nodeinfo["protocols"] = array();
    $nodeinfo["protocols"]["inbound"] = array();
    $nodeinfo["protocols"]["outbound"] = array();
    if (get_config("system", "diaspora_enabled")) {
        $nodeinfo["protocols"]["inbound"][] = "diaspora";
        $nodeinfo["protocols"]["outbound"][] = "diaspora";
    }
    $nodeinfo["protocols"]["inbound"][] = "friendica";
    $nodeinfo["protocols"]["outbound"][] = "friendica";
    if (!get_config("system", "ostatus_disabled")) {
        $nodeinfo["protocols"]["inbound"][] = "gnusocial";
        $nodeinfo["protocols"]["outbound"][] = "gnusocial";
    }
    $nodeinfo["services"] = array();
    $nodeinfo["services"]["inbound"] = array();
    $nodeinfo["services"]["outbound"] = array();
    $nodeinfo["openRegistrations"] = $a->config['register_policy'] != 0;
    $nodeinfo["usage"] = array();
    $nodeinfo["usage"]["users"] = array("total" => (int) get_config("nodeinfo", "total_users"), "activeHalfyear" => (int) get_config("nodeinfo", "active_users_halfyear"), "activeMonth" => (int) get_config("nodeinfo", "active_users_monthly"));
    $nodeinfo["usage"]["localPosts"] = (int) get_config("nodeinfo", "local_posts");
    $nodeinfo["usage"]["localComments"] = (int) get_config("nodeinfo", "local_comments");
    $nodeinfo["metadata"] = array("nodeName" => $a->config["sitename"]);
    if (nodeinfo_plugin_enabled("appnet")) {
        $nodeinfo["services"]["inbound"][] = "appnet";
    }
    if (nodeinfo_plugin_enabled("appnet") or nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "appnet";
    }
    if (nodeinfo_plugin_enabled("blogger")) {
        $nodeinfo["services"]["outbound"][] = "blogger";
    }
    if (nodeinfo_plugin_enabled("dwpost")) {
        $nodeinfo["services"]["outbound"][] = "dreamwidth";
    }
    if (nodeinfo_plugin_enabled("fbpost") or nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "facebook";
    }
    if (nodeinfo_plugin_enabled("statusnet")) {
        $nodeinfo["services"]["inbound"][] = "gnusocial";
        $nodeinfo["services"]["outbound"][] = "gnusocial";
    }
    if (nodeinfo_plugin_enabled("gpluspost") or nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "google";
    }
    if (nodeinfo_plugin_enabled("ijpost")) {
        $nodeinfo["services"]["outbound"][] = "insanejournal";
    }
    if (nodeinfo_plugin_enabled("libertree")) {
        $nodeinfo["services"]["outbound"][] = "libertree";
    }
    if (nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "linkedin";
    }
    if (nodeinfo_plugin_enabled("ljpost")) {
        $nodeinfo["services"]["outbound"][] = "livejournal";
    }
    if (nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "pinterest";
    }
    if (nodeinfo_plugin_enabled("posterous")) {
        $nodeinfo["services"]["outbound"][] = "posterous";
    }
    if (nodeinfo_plugin_enabled("pumpio")) {
        $nodeinfo["services"]["inbound"][] = "pumpio";
        $nodeinfo["services"]["outbound"][] = "pumpio";
    }
    // redmatrix
    if ($smtp) {
        $nodeinfo["services"]["outbound"][] = "smtp";
    }
    if (nodeinfo_plugin_enabled("tumblr")) {
        $nodeinfo["services"]["outbound"][] = "tumblr";
    }
    if (nodeinfo_plugin_enabled("twitter") or nodeinfo_plugin_enabled("buffer")) {
        $nodeinfo["services"]["outbound"][] = "twitter";
    }
    if (nodeinfo_plugin_enabled("wppost")) {
        $nodeinfo["services"]["outbound"][] = "wordpress";
    }
    $nodeinfo["metadata"]["protocols"] = $nodeinfo["protocols"];
    $nodeinfo["metadata"]["protocols"]["outbound"][] = "atom1.0";
    $nodeinfo["metadata"]["protocols"]["inbound"][] = "atom1.0";
    $nodeinfo["metadata"]["protocols"]["inbound"][] = "rss2.0";
    $nodeinfo["metadata"]["services"] = $nodeinfo["services"];
    if (nodeinfo_plugin_enabled("twitter")) {
        $nodeinfo["metadata"]["services"]["inbound"][] = "twitter";
    }
    header('Content-type: application/json; charset=utf-8');
    echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    exit;
}
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();
}
Beispiel #18
0
function dfrn_poll_init(&$a)
{
    $dfrn_id = x($_GET, 'dfrn_id') ? $_GET['dfrn_id'] : '';
    $type = x($_GET, 'type') ? $_GET['type'] : 'data';
    $last_update = x($_GET, 'last_update') ? $_GET['last_update'] : '';
    $destination_url = x($_GET, 'destination_url') ? $_GET['destination_url'] : '';
    $challenge = x($_GET, 'challenge') ? $_GET['challenge'] : '';
    $sec = x($_GET, 'sec') ? $_GET['sec'] : '';
    $dfrn_version = x($_GET, 'dfrn_version') ? (double) $_GET['dfrn_version'] : 2.0;
    $perm = x($_GET, 'perm') ? $_GET['perm'] : 'r';
    $quiet = x($_GET, 'quiet') ? true : false;
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    if ($dfrn_id === '' && !x($_POST, 'dfrn_id')) {
        if (get_config('system', 'block_public') && !local_user() && !remote_user()) {
            http_status_exit(403);
        }
        $user = '';
        if ($a->argc > 1) {
            $r = q("SELECT `hidewall`,`nickname` FROM `user` WHERE `user`.`nickname` = '%s' LIMIT 1", dbesc($a->argv[1]));
            if (!$r) {
                http_status_exit(404);
            }
            if ($r[0]['hidewall'] && !local_user()) {
                http_status_exit(403);
            }
            $user = $r[0]['nickname'];
        }
        logger('dfrn_poll: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $user);
        header("Content-type: application/atom+xml");
        echo get_feed_for($a, '', $user, $last_update);
        killme();
    }
    if ($type === 'profile' && !strlen($sec)) {
        $sql_extra = '';
        switch ($direction) {
            case -1:
                $sql_extra = sprintf(" AND ( `dfrn-id` = '%s' OR `issued-id` = '%s' ) ", dbesc($dfrn_id), 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 `contact`.*, `user`.`username`, `user`.`nickname`\n\t\t\tFROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\tAND `user`.`nickname` = '%s' {$sql_extra} LIMIT 1", dbesc($a->argv[1]));
        if (count($r)) {
            $s = fetch_url($r[0]['poll'] . '?dfrn_id=' . $my_id . '&type=profile-check');
            logger("dfrn_poll: old profile returns " . $s, LOGGER_DATA);
            if (strlen($s)) {
                $xml = parse_xml_string($s);
                if ((int) $xml->status == 1) {
                    $_SESSION['authenticated'] = 1;
                    if (!x($_SESSION, 'remote')) {
                        $_SESSION['remote'] = array();
                    }
                    $_SESSION['remote'][] = array('cid' => $r[0]['id'], 'uid' => $r[0]['uid'], 'url' => $r[0]['url']);
                    $_SESSION['visitor_id'] = $r[0]['id'];
                    $_SESSION['visitor_home'] = $r[0]['url'];
                    $_SESSION['visitor_handle'] = $r[0]['addr'];
                    $_SESSION['visitor_visiting'] = $r[0]['uid'];
                    if (!$quiet) {
                        info(sprintf(t('%1$s welcomes %2$s'), $r[0]['username'], $r[0]['name']) . EOL);
                    }
                    // Visitors get 1 day session.
                    $session_id = session_id();
                    $expire = time() + 86400;
                    q("UPDATE `session` SET `expire` = '%s' WHERE `sid` = '%s'", dbesc($expire), dbesc($session_id));
                }
            }
            $profile = $r[0]['nickname'];
            goaway(strlen($destination_url) ? $destination_url : $a->get_baseurl() . '/profile/' . $profile);
        }
        goaway(z_root());
    }
    if ($type === 'profile-check' && $dfrn_version < 2.2) {
        if (strlen($challenge) && strlen($sec)) {
            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
        } else {
            // old protocol
            switch ($direction) {
                case 1:
                    $dfrn_id = '0:' . $dfrn_id;
                    break;
                case 0:
                    $dfrn_id = '1:' . $dfrn_id;
                    break;
                default:
                    break;
            }
            q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time()));
            $r = q("SELECT * FROM `profile_check` WHERE `dfrn_id` = '%s' ORDER BY `expire` DESC", dbesc($dfrn_id));
            if (count($r)) {
                xml_status(1);
                return;
                // NOTREACHED
            }
            xml_status(0);
            return;
            // NOTREACHED
        }
    }
}
Beispiel #19
0
/**
 * @brief
 *
 * @param array $channel
 * @param string $observer_hash
 * @param array $params
 * @return string
 */
function get_feed_for($channel, $observer_hash, $params)
{
    if (!channel) {
        http_status_exit(401);
    }
    if ($params['pages']) {
        if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_pages')) {
            http_status_exit(403);
        }
    } else {
        if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_stream')) {
            http_status_exit(403);
        }
    }
    $items = items_fetch(array('wall' => '1', 'datequery' => $params['begin'], 'datequery2' => $params['end'], 'start' => $params['start'], 'records' => $params['records'], 'direction' => $params['direction'], 'pages' => $params['pages'], 'order' => 'post', 'top' => $params['top']), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module);
    $feed_template = get_markup_template('atom_feed.tpl');
    $atom = '';
    $atom .= replace_macros($feed_template, array('$version' => xmlify(RED_VERSION), '$red' => xmlify(PLATFORM_NAME), '$feed_id' => xmlify($channel['xchan_url']), '$feed_title' => xmlify($channel['channel_name']), '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)), '$hub' => '', '$salmon' => '', '$name' => xmlify($channel['channel_name']), '$profile_page' => xmlify($channel['xchan_url']), '$mimephoto' => xmlify($channel['xchan_photo_mimetype']), '$photo' => xmlify($channel['xchan_photo_l']), '$thumb' => xmlify($channel['xchan_photo_m']), '$picdate' => '', '$uridate' => '', '$namdate' => '', '$birthday' => '', '$community' => ''));
    call_hooks('atom_feed', $atom);
    if ($items) {
        $type = 'html';
        foreach ($items as $item) {
            if ($item['item_private']) {
                continue;
            }
            /** @BUG $owner is undefined in this call */
            $atom .= atom_entry($item, $type, null, $owner, true);
        }
    }
    call_hooks('atom_feed_end', $atom);
    $atom .= '</feed>' . "\r\n";
    return $atom;
}
Beispiel #20
0
function poco_init(&$a)
{
    require_once "include/bbcode.php";
    $system_mode = false;
    if (intval(get_config('system', 'block_public')) || get_config('system', 'block_local_dir')) {
        http_status_exit(401);
    }
    if ($a->argc > 1) {
        $user = notags(trim($a->argv[1]));
    }
    if (!x($user)) {
        $c = q("SELECT * FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1");
        if (!count($c)) {
            http_status_exit(401);
        }
        $system_mode = true;
    }
    $format = $_GET['format'] ? $_GET['format'] : 'json';
    $justme = false;
    $global = false;
    if ($a->argc > 1 && $a->argv[1] === '@global') {
        $global = true;
        $update_limit = date("Y-m-d H:i:s", time() - 30 * 86400);
    }
    if ($a->argc > 2 && $a->argv[2] === '@me') {
        $justme = true;
    }
    if ($a->argc > 3 && $a->argv[3] === '@all') {
        $justme = false;
    }
    if ($a->argc > 3 && $a->argv[3] === '@self') {
        $justme = true;
    }
    if ($a->argc > 4 && intval($a->argv[4]) && $justme == false) {
        $cid = intval($a->argv[4]);
    }
    if (!$system_mode and !$global) {
        $r = q("SELECT `user`.*,`profile`.`hide-friends` from user left join profile on `user`.`uid` = `profile`.`uid`\n\t\t\twhere `user`.`nickname` = '%s' and `profile`.`is-default` = 1 limit 1", dbesc($user));
        if (!count($r) || $r[0]['hidewall'] || $r[0]['hide-friends']) {
            http_status_exit(404);
        }
        $user = $r[0];
    }
    if ($justme) {
        $sql_extra = " AND `contact`.`self` = 1 ";
    }
    //	else
    //		$sql_extra = " AND `contact`.`self` = 0 ";
    if ($cid) {
        $sql_extra = sprintf(" AND `contact`.`id` = %d ", intval($cid));
    }
    if (x($_GET, 'updatedSince')) {
        $update_limit = date("Y-m-d H:i:s", strtotime($_GET['updatedSince']));
    }
    if ($global) {
        //$r = q("SELECT count(*) AS `total` FROM `gcontact` WHERE `updated` >= '%s' AND ((`last_contact` >= `last_failure`) OR (`updated` >= `last_failure`))  AND `network` IN ('%s')",
        $r = q("SELECT count(*) AS `total` FROM `gcontact` WHERE `updated` >= '%s' AND `updated` >= `last_failure`  AND `network` IN ('%s', '%s', '%s')", dbesc($update_limit), dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS));
    } elseif ($system_mode) {
        $r = q("SELECT count(*) AS `total` FROM `contact` WHERE `self` = 1 AND `network` IN ('%s', '%s', '%s', '%s')\n\t\t\tAND (`success_update` >= `failure_update` OR `last-item` >= `failure_update`)\n\t\t\tAND `uid` IN (SELECT `uid` FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1) ", dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET));
    } else {
        $r = q("SELECT count(*) AS `total` FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0\n\t\t\tAND (`success_update` >= `failure_update` OR `last-item` >= `failure_update`)\n\t\t\tAND `network` IN ('%s', '%s', '%s', '%s') {$sql_extra}", intval($user['uid']), dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET));
    }
    if (count($r)) {
        $totalResults = intval($r[0]['total']);
    } else {
        $totalResults = 0;
    }
    $startIndex = intval($_GET['startIndex']);
    if (!$startIndex) {
        $startIndex = 0;
    }
    $itemsPerPage = x($_GET, 'count') && intval($_GET['count']) ? intval($_GET['count']) : $totalResults;
    if ($global) {
        logger("Start global query", LOGGER_DEBUG);
        //$r = q("SELECT * FROM `gcontact` WHERE `updated` > '%s' AND `network` IN ('%s') AND ((`last_contact` >= `last_failure`) OR (`updated` > `last_failure`)) LIMIT %d, %d",
        $r = q("SELECT * FROM `gcontact` WHERE `updated` > '%s' AND `network` IN ('%s', '%s', '%s') AND `updated` > `last_failure`\n\t\t\tORDER BY `updated` DESC LIMIT %d, %d", dbesc($update_limit), dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), intval($startIndex), intval($itemsPerPage));
    } elseif ($system_mode) {
        logger("Start system mode query", LOGGER_DEBUG);
        $r = q("SELECT `contact`.*, `profile`.`about` AS `pabout`, `profile`.`locality` AS `plocation`, `profile`.`pub_keywords`, `profile`.`gender` AS `pgender`,\n\t\t\t`profile`.`address` AS `paddress`, `profile`.`region` AS `pregion`, `profile`.`postal-code` AS `ppostalcode`, `profile`.`country-name` AS `pcountry`\n\t\t\tFROM `contact` INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid`\n\t\t\tWHERE `self` = 1 AND `network` IN ('%s', '%s', '%s', '%s') AND `profile`.`is-default`\n\t\t\tAND ((`contact`.`success_update` >= `contact`.`failure_update`) OR (`contact`.`last-item` >= `contact`.`failure_update`))\n\t\t\tAND `contact`.`uid` IN (SELECT `uid` FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1) LIMIT %d, %d", dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET), intval($startIndex), intval($itemsPerPage));
    } else {
        logger("Start query for user " . $user['nickname'], LOGGER_DEBUG);
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0\n\t\t\tAND (`success_update` >= `failure_update` OR `last-item` >= `failure_update`)\n\t\t\tAND `network` IN ('%s', '%s', '%s', '%s') {$sql_extra} LIMIT %d, %d", intval($user['uid']), dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET), intval($startIndex), intval($itemsPerPage));
    }
    logger("Query done", LOGGER_DEBUG);
    $ret = array();
    if (x($_GET, 'sorted')) {
        $ret['sorted'] = false;
    }
    if (x($_GET, 'filtered')) {
        $ret['filtered'] = false;
    }
    if (x($_GET, 'updatedSince') and !$global) {
        $ret['updatedSince'] = false;
    }
    $ret['startIndex'] = (int) $startIndex;
    $ret['itemsPerPage'] = (int) $itemsPerPage;
    $ret['totalResults'] = (int) $totalResults;
    $ret['entry'] = array();
    $fields_ret = array('id' => false, 'displayName' => false, 'urls' => false, 'updated' => false, 'preferredUsername' => false, 'photos' => false, 'aboutMe' => false, 'currentLocation' => false, 'network' => false, 'gender' => false, 'tags' => false, 'address' => false, 'generation' => false);
    if (!x($_GET, 'fields') || $_GET['fields'] === '@all') {
        foreach ($fields_ret as $k => $v) {
            $fields_ret[$k] = true;
        }
    } else {
        $fields_req = explode(',', $_GET['fields']);
        foreach ($fields_req as $f) {
            $fields_ret[trim($f)] = true;
        }
    }
    if (is_array($r)) {
        if (count($r)) {
            foreach ($r as $rr) {
                if (!isset($rr['generation'])) {
                    if ($global) {
                        $rr['generation'] = 3;
                    } elseif ($system_mode) {
                        $rr['generation'] = 1;
                    } else {
                        $rr['generation'] = 2;
                    }
                }
                if ($rr['about'] == "" and isset($rr['pabout'])) {
                    $rr['about'] = $rr['pabout'];
                }
                if ($rr['location'] == "") {
                    if (isset($rr['plocation'])) {
                        $rr['location'] = $rr['plocation'];
                    }
                    if (isset($rr['pregion']) and $rr['pregion'] != "") {
                        if ($rr['location'] != "") {
                            $rr['location'] .= ", ";
                        }
                        $rr['location'] .= $rr['pregion'];
                    }
                    if (isset($rr['pcountry']) and $rr['pcountry'] != "") {
                        if ($rr['location'] != "") {
                            $rr['location'] .= ", ";
                        }
                        $rr['location'] .= $rr['pcountry'];
                    }
                }
                if ($rr['gender'] == "" and isset($rr['pgender'])) {
                    $rr['gender'] = $rr['pgender'];
                }
                if ($rr['keywords'] == "" and isset($rr['pub_keywords'])) {
                    $rr['keywords'] = $rr['pub_keywords'];
                }
                $about = Cache::get("about:" . $rr['updated'] . ":" . $rr['nurl']);
                if (is_null($about)) {
                    $about = bbcode($rr['about'], false, false);
                    Cache::set("about:" . $rr['updated'] . ":" . $rr['nurl'], $about);
                }
                $entry = array();
                if ($fields_ret['id']) {
                    $entry['id'] = (int) $rr['id'];
                }
                if ($fields_ret['displayName']) {
                    $entry['displayName'] = $rr['name'];
                }
                if ($fields_ret['aboutMe']) {
                    $entry['aboutMe'] = $about;
                }
                if ($fields_ret['currentLocation']) {
                    $entry['currentLocation'] = $rr['location'];
                }
                if ($fields_ret['gender']) {
                    $entry['gender'] = $rr['gender'];
                }
                if ($fields_ret['generation']) {
                    $entry['generation'] = (int) $rr['generation'];
                }
                if ($fields_ret['urls']) {
                    $entry['urls'] = array(array('value' => $rr['url'], 'type' => 'profile'));
                    if ($rr['addr'] && $rr['network'] !== NETWORK_MAIL) {
                        $entry['urls'][] = array('value' => 'acct:' . $rr['addr'], 'type' => 'webfinger');
                    }
                }
                if ($fields_ret['preferredUsername']) {
                    $entry['preferredUsername'] = $rr['nick'];
                }
                if ($fields_ret['updated']) {
                    if (!$global) {
                        $entry['updated'] = $rr['success_update'];
                        if ($rr['name-date'] > $entry['updated']) {
                            $entry['updated'] = $rr['name-date'];
                        }
                        if ($rr['uri-date'] > $entry['updated']) {
                            $entry['updated'] = $rr['uri-date'];
                        }
                        if ($rr['avatar-date'] > $entry['updated']) {
                            $entry['updated'] = $rr['avatar-date'];
                        }
                    } else {
                        $entry['updated'] = $rr['updated'];
                    }
                    $entry['updated'] = date("c", strtotime($entry['updated']));
                }
                if ($fields_ret['photos']) {
                    $entry['photos'] = array(array('value' => $rr['photo'], 'type' => 'profile'));
                }
                if ($fields_ret['network']) {
                    $entry['network'] = $rr['network'];
                    if ($entry['network'] == NETWORK_STATUSNET) {
                        $entry['network'] = NETWORK_OSTATUS;
                    }
                    if ($entry['network'] == "" and $rr['self']) {
                        $entry['network'] = NETWORK_DFRN;
                    }
                }
                if ($fields_ret['tags']) {
                    $tags = str_replace(",", " ", $rr['keywords']);
                    $tags = explode(" ", $tags);
                    $cleaned = array();
                    foreach ($tags as $tag) {
                        $tag = trim(strtolower($tag));
                        if ($tag != "") {
                            $cleaned[] = $tag;
                        }
                    }
                    $entry['tags'] = array($cleaned);
                }
                if ($fields_ret['address']) {
                    $entry['address'] = array();
                    // Deactivated. It just reveals too much data. (Although its from the default profile)
                    //if (isset($rr['paddress']))
                    //	 $entry['address']['streetAddress'] = $rr['paddress'];
                    if (isset($rr['plocation'])) {
                        $entry['address']['locality'] = $rr['plocation'];
                    }
                    if (isset($rr['pregion'])) {
                        $entry['address']['region'] = $rr['pregion'];
                    }
                    // See above
                    //if (isset($rr['ppostalcode']))
                    //	 $entry['address']['postalCode'] = $rr['ppostalcode'];
                    if (isset($rr['pcountry'])) {
                        $entry['address']['country'] = $rr['pcountry'];
                    }
                }
                $ret['entry'][] = $entry;
            }
        } else {
            $ret['entry'][] = array();
        }
    } else {
        http_status_exit(500);
    }
    logger("End of poco", LOGGER_DEBUG);
    if ($format === 'xml') {
        header('Content-type: text/xml');
        echo replace_macros(get_markup_template('poco_xml.tpl'), array_xmlify(array('$response' => $ret)));
        killme();
    }
    if ($format === 'json') {
        header('Content-type: application/json');
        echo json_encode($ret);
        killme();
    } else {
        http_status_exit(500);
    }
}
Beispiel #21
0
/**
 * @brief Fires up the SabreDAV server.
 *
 * @param App &$a
 */
function cloud_init(&$a)
{
    require_once 'include/reddav.php';
    if (!is_dir('store')) {
        os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
    }
    $which = null;
    if (argc() > 1) {
        $which = argv(1);
    }
    $profile = 0;
    $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which . '" />' . "\r\n";
    if ($which) {
        profile_load($a, $which, $profile);
    }
    $auth = new RedDAV\RedBasicAuth();
    $ob_hash = get_observer_hash();
    if ($ob_hash) {
        if (local_channel()) {
            $channel = $a->get_channel();
            $auth->setCurrentUser($channel['channel_address']);
            $auth->channel_id = $channel['channel_id'];
            $auth->channel_hash = $channel['channel_hash'];
            $auth->channel_account_id = $channel['channel_account_id'];
            if ($channel['channel_timezone']) {
                $auth->setTimezone($channel['channel_timezone']);
            }
        }
        $auth->observer = $ob_hash;
    }
    if ($_GET['davguest']) {
        $_SESSION['davguest'] = true;
    }
    $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
    $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']);
    $_SERVER['QUERY_STRING'] = preg_replace('/[\\?&]davguest=(.*?)([\\?&]|$)/ism', '', $_SERVER['QUERY_STRING']);
    $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']);
    $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']);
    $_SERVER['REQUEST_URI'] = preg_replace('/[\\?&]davguest=(.*?)([\\?&]|$)/ism', '', $_SERVER['REQUEST_URI']);
    $rootDirectory = new RedDAV\RedDirectory('/', $auth);
    // A SabreDAV server-object
    $server = new DAV\Server($rootDirectory);
    // prevent overwriting changes each other with a lock backend
    $lockBackend = new DAV\Locks\Backend\File('store/[data]/locks');
    $lockPlugin = new DAV\Locks\Plugin($lockBackend);
    $server->addPlugin($lockPlugin);
    $is_readable = false;
    if ($_SERVER['REQUEST_METHOD'] === 'GET') {
        try {
            $x = RedFileData('/' . $a->cmd, $auth);
        } catch (\Exception $e) {
            if ($e instanceof Sabre\DAV\Exception\Forbidden) {
                http_status_exit(401, 'Permission denied.');
            }
        }
    }
    require_once 'include/RedDAV/RedBrowser.php';
    // provide a directory view for the cloud in Hubzilla
    $browser = new RedDAV\RedBrowser($auth);
    $auth->setBrowserPlugin($browser);
    $server->addPlugin($browser);
    // Experimental QuotaPlugin
    //	require_once('include/RedDAV/QuotaPlugin.php');
    //	$server->addPlugin(new RedDAV\QuotaPlugin($auth));
    // All we need to do now, is to fire up the server
    $server->exec();
    killme();
}
Beispiel #22
0
function poco_init(&$a)
{
    $system_mode = false;
    if (intval(get_config('system', 'block_public'))) {
        http_status_exit(401);
    }
    if ($a->argc > 1) {
        $user = notags(trim($a->argv[1]));
    }
    if (!x($user)) {
        $c = q("select * from pconfig where cat = 'system' and k = 'suggestme' and v = 1");
        if (!count($c)) {
            http_status_exit(401);
        }
        $system_mode = true;
    }
    $format = $_GET['format'] ? $_GET['format'] : 'json';
    $justme = false;
    if ($a->argc > 2 && $a->argv[2] === '@me') {
        $justme = true;
    }
    if ($a->argc > 3 && $a->argv[3] === '@all') {
        $justme = false;
    }
    if ($a->argc > 3 && $a->argv[3] === '@self') {
        $justme = true;
    }
    if ($a->argc > 4 && intval($a->argv[4]) && $justme == false) {
        $cid = intval($a->argv[4]);
    }
    if (!$system_mode) {
        $r = q("SELECT `user`.*,`profile`.`hide-friends` from user left join profile on `user`.`uid` = `profile`.`uid`\n\t\t\twhere `user`.`nickname` = '%s' and `profile`.`is-default` = 1 limit 1", dbesc($user));
        if (!count($r) || $r[0]['hidewall'] || $r[0]['hide-friends']) {
            http_status_exit(404);
        }
        $user = $r[0];
    }
    if ($justme) {
        $sql_extra = " and `contact`.`self` = 1 ";
    }
    if ($cid) {
        $sql_extra = sprintf(" and `contact`.`id` = %d ", intval($cid));
    }
    if ($system_mode) {
        $r = q("SELECT count(*) as `total` from `contact` where self = 1 \n\t\t\tand uid in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = 1) ");
    } else {
        $r = q("SELECT count(*) as `total` from `contact` where `uid` = %d and blocked = 0 and pending = 0 and hidden = 0\n\t\t\t{$sql_extra} ", intval($user['uid']));
    }
    if (count($r)) {
        $totalResults = intval($r[0]['total']);
    } else {
        $totalResults = 0;
    }
    $startIndex = intval($_GET['startIndex']);
    if (!$startIndex) {
        $startIndex = 0;
    }
    $itemsPerPage = x($_GET, 'count') && intval($_GET['count']) ? intval($_GET['count']) : $totalResults;
    if ($system_mode) {
        $r = q("SELECT * from contact where self = 1 \n\t\t\tand uid in (select uid from pconfig where cat = 'system' and k = 'suggestme' and v = 1) limit %d, %d ", intval($startIndex), intval($itemsPerPage));
    } else {
        $r = q("SELECT * from `contact` where `uid` = %d and blocked = 0 and pending = 0 and hidden = 0\n\t\t\t{$sql_extra} LIMIT %d, %d", intval($user['uid']), intval($startIndex), intval($itemsPerPage));
    }
    $ret = array();
    if (x($_GET, 'sorted')) {
        $ret['sorted'] = 'false';
    }
    if (x($_GET, 'filtered')) {
        $ret['filtered'] = 'false';
    }
    if (x($_GET, 'updatedSince')) {
        $ret['updateSince'] = 'false';
    }
    $ret['startIndex'] = (string) $startIndex;
    $ret['itemsPerPage'] = (string) $itemsPerPage;
    $ret['totalResults'] = (string) $totalResults;
    $ret['entry'] = array();
    $fields_ret = array('id' => false, 'displayName' => false, 'urls' => false, 'preferredUsername' => false, 'photos' => false);
    if (!x($_GET, 'fields') || $_GET['fields'] === '@all') {
        foreach ($fields_ret as $k => $v) {
            $fields_ret[$k] = true;
        }
    } else {
        $fields_req = explode(',', $_GET['fields']);
        foreach ($fields_req as $f) {
            $fields_ret[trim($f)] = true;
        }
    }
    if (is_array($r)) {
        if (count($r)) {
            foreach ($r as $rr) {
                $entry = array();
                if ($fields_ret['id']) {
                    $entry['id'] = $rr['id'];
                }
                if ($fields_ret['displayName']) {
                    $entry['displayName'] = $rr['name'];
                }
                if ($fields_ret['urls']) {
                    $entry['urls'] = array(array('value' => $rr['url'], 'type' => 'profile'));
                    if ($rr['addr'] && $rr['network'] !== NETWORK_MAIL) {
                        $entry['urls'][] = array('value' => 'acct:' . $rr['addr'], 'type' => 'webfinger');
                    }
                }
                if ($fields_ret['preferredUsername']) {
                    $entry['preferredUsername'] = $rr['nick'];
                }
                if ($fields_ret['photos']) {
                    $entry['photos'] = array(array('value' => $rr['photo'], 'type' => 'profile'));
                }
                $ret['entry'][] = $entry;
            }
        } else {
            $ret['entry'][] = array();
        }
    } else {
        http_status_exit(500);
    }
    if ($format === 'xml') {
        header('Content-type: text/xml');
        echo replace_macros(get_markup_template('poco_xml.tpl'), array_xmlify(array('$response' => $ret)));
        http_status_exit(500);
    }
    if ($format === 'json') {
        header('Content-type: application/json');
        echo json_encode($ret);
        killme();
    } else {
        http_status_exit(500);
    }
}
Beispiel #23
0
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');
}
Beispiel #24
0
/**
 * @brief Fires up the SabreDAV server.
 *
 * @param App &$a
 */
function cloud_init(&$a)
{
    // call ($currenttheme)_init since we're operating outside of index.php
    $theme_info_file = "view/theme/" . current_theme() . "/php/theme.php";
    if (file_exists($theme_info_file)) {
        require_once $theme_info_file;
        if (function_exists(str_replace('-', '_', current_theme()) . '_init')) {
            $func = str_replace('-', '_', current_theme()) . '_init';
            $func($a);
        }
    }
    require_once 'include/reddav.php';
    if (!is_dir('store')) {
        os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
    }
    $which = null;
    if (argc() > 1) {
        $which = argv(1);
    }
    $profile = 0;
    $channel = $a->get_channel();
    $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which . '" />' . "\r\n";
    if ($which) {
        profile_load($a, $which, $profile);
    }
    $auth = new RedBasicAuth();
    $ob_hash = get_observer_hash();
    if ($ob_hash) {
        if (local_user()) {
            $channel = $a->get_channel();
            $auth->setCurrentUser($channel['channel_address']);
            $auth->channel_name = $channel['channel_address'];
            $auth->channel_id = $channel['channel_id'];
            $auth->channel_hash = $channel['channel_hash'];
            $auth->channel_account_id = $channel['channel_account_id'];
            if ($channel['channel_timezone']) {
                $auth->timezone = $channel['channel_timezone'];
            }
        }
        $auth->observer = $ob_hash;
    }
    if ($_GET['davguest']) {
        $_SESSION['davguest'] = true;
    }
    $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
    $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']);
    $_SERVER['QUERY_STRING'] = preg_replace('/[\\?&]davguest=(.*?)([\\?&]|$)/ism', '', $_SERVER['QUERY_STRING']);
    $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']);
    $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']);
    $_SERVER['REQUEST_URI'] = preg_replace('/[\\?&]davguest=(.*?)([\\?&]|$)/ism', '', $_SERVER['REQUEST_URI']);
    $rootDirectory = new RedDirectory('/', $auth);
    // A SabreDAV server-object
    $server = new DAV\Server($rootDirectory);
    // prevent overwriting changes each other with a lock backend
    $lockBackend = new DAV\Locks\Backend\File('store/[data]/locks');
    $lockPlugin = new DAV\Locks\Plugin($lockBackend);
    $server->addPlugin($lockPlugin);
    // The next section of code allows us to bypass prompting for http-auth if a FILE is being accessed anonymously and permissions
    // allow this. This way one can create hotlinks to public media files in their cloud and anonymous viewers won't get asked to login.
    // If a DIRECTORY is accessed or there are permission issues accessing the file and we aren't previously authenticated via zot,
    // prompt for HTTP-auth. This will be the default case for mounting a DAV directory.
    // In order to avoid prompting for passwords for viewing a DIRECTORY, add the URL query parameter 'davguest=1'
    $isapublic_file = false;
    $davguest = x($_SESSION, 'davguest') ? true : false;
    if (!$auth->observer && $_SERVER['REQUEST_METHOD'] === 'GET') {
        try {
            $x = RedFileData('/' . $a->cmd, $auth);
            if ($x instanceof RedFile) {
                $isapublic_file = true;
            }
        } catch (Exception $e) {
            $isapublic_file = false;
        }
    }
    if (!$auth->observer && !$isapublic_file && !$davguest) {
        try {
            $auth->Authenticate($server, t('Red Matrix - Guests: Username: {your email address}, Password: +++'));
        } catch (Exception $e) {
            logger('mod_cloud: auth exception' . $e->getMessage());
            http_status_exit($e->getHTTPCode(), $e->getMessage());
        }
    }
    // provide a directory view for the cloud in Red Matrix
    $browser = new RedBrowser($auth);
    $auth->setBrowserPlugin($browser);
    $server->addPlugin($browser);
    // All we need to do now, is to fire up the server
    $server->exec();
    killme();
}
/**
 * @brief Process atom feed and update anything/everything we might need to update.
 *
 * @param array $xml
 *   The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
 * @param $importer
 *   The contact_record (joined to user_record) of the local user who owns this
 *   relationship. It is this person's stuff that is going to be updated.
 * @param $contact
 *   The person who is sending us stuff. If not set, we MAY be processing a "follow" activity
 *   from an external network and MAY create an appropriate contact record. Otherwise, we MUST
 *   have a contact record.
 * @param int $pass by default ($pass = 0) we cannot guarantee that a parent item has been
 *   imported prior to its children being seen in the stream unless we are certain
 *   of how the feed is arranged/ordered.
 *  * With $pass = 1, we only pull parent items out of the stream.
 *  * With $pass = 2, we only pull children (comments/likes).
 *
 * So running this twice, first with pass 1 and then with pass 2 will do the right
 * thing regardless of feed ordering. This won't be adequate in a fully-threaded
 * model where comments can have sub-threads. That would require some massive sorting
 * to get all the feed items into a mostly linear ordering, and might still require
 * recursion.
 */
function consume_feed($xml, $importer, &$contact, $pass = 0)
{
    require_once 'library/simplepie/simplepie.inc';
    if (!strlen($xml)) {
        logger('consume_feed: empty input');
        return;
    }
    $sys_expire = intval(get_config('system', 'default_expire_days'));
    $chn_expire = intval($importer['channel_expire_days']);
    $expire_days = $sys_expire;
    if ($chn_expire != 0 && $chn_expire < $sys_expire) {
        $expire_days = $chn_expire;
    }
    // logger('expire_days: ' . $expire_days);
    $feed = new SimplePie();
    $feed->set_raw_data($xml);
    $feed->init();
    if ($feed->error()) {
        logger('consume_feed: Error parsing XML: ' . $feed->error());
    }
    $permalink = $feed->get_permalink();
    // Check at the feed level for updated contact name and/or photo
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries) && $pass != 2) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $mid = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
                }
            }
            if ($deleted && is_array($contact)) {
                $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1", dbesc(base64url_encode($mid)), dbesc($contact['xchan_hash']), intval($importer['channel_id']));
                if ($r) {
                    $item = $r[0];
                    if (!intval($item['item_deleted'])) {
                        logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
                        drop_item($item['id'], false);
                    }
                }
            }
        }
    }
    // Now process the feed
    if ($feed->get_item_quantity()) {
        logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
        $items = $feed->get_items();
        foreach ($items as $item) {
            $is_reply = false;
            $item_id = base64url_encode($item->get_id());
            logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
            $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
            if (isset($rawthread[0]['attribs']['']['ref'])) {
                $is_reply = true;
                $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
            }
            if ($is_reply) {
                if ($pass == 1) {
                    continue;
                }
                // Have we seen it? If not, import it.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if ($contact['xchan_network'] === 'rss') {
                    $datarray['public_policy'] = 'specific';
                    $datarray['comment_policy'] = 'none';
                }
                if (!x($author, 'author_name') || $author['author_is_feed']) {
                    $author['author_name'] = $contact['xchan_name'];
                }
                if (!x($author, 'author_link') || $author['author_is_feed']) {
                    $author['author_link'] = $contact['xchan_url'];
                }
                if (!x($author, 'author_photo') || $author['author_is_feed']) {
                    $author['author_photo'] = $contact['xchan_photo_m'];
                }
                $datarray['author_xchan'] = '';
                if ($author['author_link'] != $contact['xchan_url']) {
                    $x = import_author_unknown(array('name' => $author['author_name'], 'url' => $author['author_link'], 'photo' => array('src' => $author['author_photo'])));
                    if ($x) {
                        $datarray['author_xchan'] = $x;
                    }
                }
                if (!$datarray['author_xchan']) {
                    $datarray['author_xchan'] = $contact['xchan_hash'];
                }
                $datarray['owner_xchan'] = $contact['xchan_hash'];
                $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']));
                // Update content if 'updated' changes
                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']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $datarray['parent_mid'] = $parent_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'];
                continue;
            } else {
                // Head post of a conversation. Have we seen it? If not, import it.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if ($contact['xchan_network'] === 'rss') {
                    $datarray['public_policy'] = 'specific';
                    $datarray['comment_policy'] = 'none';
                }
                if (is_array($contact)) {
                    if (!x($author, 'author_name') || $author['author_is_feed']) {
                        $author['author_name'] = $contact['xchan_name'];
                    }
                    if (!x($author, 'author_link') || $author['author_is_feed']) {
                        $author['author_link'] = $contact['xchan_url'];
                    }
                    if (!x($author, 'author_photo') || $author['author_is_feed']) {
                        $author['author_photo'] = $contact['xchan_photo_m'];
                    }
                }
                if (!x($author, 'author_name') || !x($author, 'author_link')) {
                    logger('consume_feed: no author information! ' . print_r($author, true));
                    continue;
                }
                $datarray['author_xchan'] = '';
                if (activity_match($datarray['verb'], ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) {
                    $cb = array('item' => $datarray, 'channel' => $importer, 'xchan' => null, 'author' => $author, 'caught' => false);
                    call_hooks('follow_from_feed', $cb);
                    if ($cb['caught']) {
                        if ($cb['return_code']) {
                            http_status_exit($cb['return_code']);
                        }
                        continue;
                    }
                }
                if ($author['author_link'] != $contact['xchan_url']) {
                    $x = import_author_unknown(array('name' => $author['author_name'], 'url' => $author['author_link'], 'photo' => array('src' => $author['author_photo'])));
                    if ($x) {
                        $datarray['author_xchan'] = $x;
                    }
                }
                if (!$datarray['author_xchan']) {
                    $datarray['author_xchan'] = $contact['xchan_hash'];
                }
                $datarray['owner_xchan'] = $contact['xchan_hash'];
                if (array_key_exists('created', $datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
                    $t1 = $datarray['created'];
                    $t2 = datetime_convert('UTC', 'UTC', 'now - ' . $expire_days . 'days');
                    if ($t1 < $t2) {
                        logger('feed content older than expiration. Ignoring.', LOGGER_DEBUG, LOG_INFO);
                        continue;
                    }
                }
                $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']));
                // Update content if 'updated' changes
                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']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $datarray['parent_mid'] = $item_id;
                $datarray['uid'] = $importer['channel_id'];
                $datarray['aid'] = $importer['channel_account_id'];
                if (!link_compare($author['owner_link'], $contact['xchan_url'])) {
                    logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
                    $author['owner_name'] = $contact['name'];
                    $author['owner_link'] = $contact['url'];
                    $author['owner_avatar'] = $contact['thumb'];
                }
                if (!post_is_importable($datarray, $contact)) {
                    continue;
                }
                logger('consume_feed: author ' . print_r($author, true), LOGGER_DEBUG);
                logger('consume_feed: ' . print_r($datarray, true), LOGGER_DATA);
                $xx = item_store($datarray);
                $r = $xx['item_id'];
                continue;
            }
        }
    }
}
Beispiel #26
0
function search_content(&$a)
{
    if (get_config('system', 'block_public') && !local_user() && !remote_user()) {
        notice(t('Public access denied.') . EOL);
        return;
    }
    if (get_config('system', 'local_search') and !local_user()) {
        http_status_exit(403, array("title" => t("Public access denied."), "description" => t("Only logged in users are permitted to perform a search.")));
        killme();
        //notice(t('Public access denied.').EOL);
        //return;
    }
    if (get_config('system', 'permit_crawling') and !local_user()) {
        // Default values:
        // 10 requests are "free", after the 11th only a call per minute is allowed
        $free_crawls = intval(get_config('system', 'free_crawls'));
        if ($free_crawls == 0) {
            $free_crawls = 10;
        }
        $crawl_permit_period = intval(get_config('system', 'crawl_permit_period'));
        if ($crawl_permit_period == 0) {
            $crawl_permit_period = 10;
        }
        $remote = $_SERVER["REMOTE_ADDR"];
        $result = Cache::get("remote_search:" . $remote);
        if (!is_null($result)) {
            $resultdata = json_decode($result);
            if ($resultdata->time > time() - $crawl_permit_period and $resultdata->accesses > $free_crawls) {
                http_status_exit(429, array("title" => t("Too Many Requests"), "description" => t("Only one search per minute is permitted for not logged in users.")));
                killme();
            }
            Cache::set("remote_search:" . $remote, json_encode(array("time" => time(), "accesses" => $resultdata->accesses + 1)), CACHE_HOUR);
        } else {
            Cache::set("remote_search:" . $remote, json_encode(array("time" => time(), "accesses" => 1)), CACHE_HOUR);
        }
    }
    nav_set_selected('search');
    $o = '<h3>' . t('Search') . '</h3>';
    if (x($a->data, 'search')) {
        $search = notags(trim($a->data['search']));
    } else {
        $search = x($_GET, 'search') ? notags(trim(rawurldecode($_GET['search']))) : '';
    }
    $tag = false;
    if (x($_GET, 'tag')) {
        $tag = true;
        $search = x($_GET, 'tag') ? notags(trim(rawurldecode($_GET['tag']))) : '';
    }
    $o .= search($search, 'search-box', '/search', local_user() ? true : false, false);
    if (strpos($search, '#') === 0) {
        $tag = true;
        $search = substr($search, 1);
    }
    if (strpos($search, '@') === 0) {
        return dirfind_content($a);
    }
    if (strpos($search, '!') === 0) {
        return dirfind_content($a);
    }
    if (x($_GET, 'search-option')) {
        switch ($_GET['search-option']) {
            case 'fulltext':
                break;
            case 'tags':
                $tag = true;
                break;
            case 'contacts':
                return dirfind_content($a, "@");
                break;
            case 'forums':
                return dirfind_content($a, "!");
                break;
        }
    }
    if (!$search) {
        return $o;
    }
    if (get_config('system', 'only_tag_search')) {
        $tag = true;
    }
    // Here is the way permissions work in the search module...
    // Only public posts can be shown
    // OR your own posts if you are a logged in member
    // No items will be shown if the member has a blocked profile wall.
    if ($tag) {
        logger("Start tag search for '" . $search . "'", LOGGER_DEBUG);
        $r = q("SELECT STRAIGHT_JOIN `item`.`uri`, `item`.*, `item`.`id` AS `item_id`,\n\t\t\t\t`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`,\n\t\t\t\t`contact`.`network`, `contact`.`thumb`, `contact`.`self`, `contact`.`writable`,\n\t\t\t\t`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`\n\t\t\tFROM `term`\n\t\t\t\tINNER JOIN `item` ON `item`.`id`=`term`.`oid`\n\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`\n\t\t\tWHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`\n\t\t\t\tAND (`term`.`uid` = 0 OR (`term`.`uid` = %d AND NOT `term`.`global`)) AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`term` = '%s'\n\t\t\tORDER BY term.created DESC LIMIT %d , %d ", intval(local_user()), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), dbesc(protect_sprintf($search)), intval($a->pager['start']), intval($a->pager['itemspage']));
    } else {
        logger("Start fulltext search for '" . $search . "'", LOGGER_DEBUG);
        if (get_config('system', 'use_fulltext_engine')) {
            $sql_extra = sprintf(" AND MATCH (`item`.`body`, `item`.`title`) AGAINST ('%s' in boolean mode) ", dbesc(protect_sprintf($search)));
        } else {
            $sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search))));
        }
        $r = q("SELECT STRAIGHT_JOIN `item`.`uri`, `item`.*, `item`.`id` AS `item_id`,\n\t\t\t\t`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`,\n\t\t\t\t`contact`.`network`, `contact`.`thumb`, `contact`.`self`, `contact`.`writable`,\n\t\t\t\t`contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`\n\t\t\tFROM `item`\n\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`\n\t\t\tWHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`\n\t\t\t\tAND (`item`.`uid` = 0 OR (`item`.`uid` = %s AND (`item`.`private` OR NOT `item`.`network` IN ('%s', '%s', '%s'))))\n\t\t\t\t{$sql_extra}\n\t\t\tGROUP BY `item`.`uri` ORDER BY `item`.`id` DESC LIMIT %d , %d ", intval(local_user()), dbesc(NETWORK_DFRN), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DIASPORA), intval($a->pager['start']), intval($a->pager['itemspage']));
    }
    if (!count($r)) {
        info(t('No results.') . EOL);
        return $o;
    }
    if ($tag) {
        $title = sprintf(t('Items tagged with: %s'), $search);
    } else {
        $title = sprintf(t('Search results for: %s'), $search);
    }
    $o .= replace_macros(get_markup_template("section_title.tpl"), array('$title' => $title));
    logger("Start Conversation for '" . $search . "'", LOGGER_DEBUG);
    $o .= conversation($a, $r, 'search', false);
    $o .= alt_pager($a, count($r));
    logger("Done '" . $search . "'", LOGGER_DEBUG);
    return $o;
}
Beispiel #27
0
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 = post_var('hub_mode');
        $hub_callback = post_var('hub_callback');
        $hub_verify = post_var('hub_verify');
        $hub_verify_token = post_var('hub_verify_token');
        $hub_secret = post_var('hub_secret');
        $hub_topic = 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
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s'" . " AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nick));
        if (!count($r)) {
            logger('pubsubhubbub: local account not found: ' . $nick);
            http_status_exit(404);
        }
        $owner = $r[0];
        // abort if user's wall is supposed to be private
        if ($r[0]['hidewall']) {
            logger('pubsubhubbub: local user ' . $nick . 'has chosen to hide wall, ignoring.');
            http_status_exit(403);
        }
        // get corresponding row from contact table
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `blocked`" . " AND NOT `pending` AND `self` LIMIT 1", intval($owner['uid']));
        if (!count($r)) {
            logger('pubsubhubbub: contact not found.');
            http_status_exit(404);
        }
        $contact = $r[0];
        // sanity check that topic URLs are the same
        if (!link_compare($hub_topic, $contact['poll'])) {
            logger('pubsubhubbub: hub topic ' . $hub_topic . ' != ' . $contact['poll']);
            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)
        $body = fetch_url($hub_callback . "?" . $params);
        $ret = $a->get_curl_code();
        // give up if the HTTP return code wasn't a success (2xx)
        if ($ret < 200 || $ret > 299) {
            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($body) !== $hub_challenge) {
            logger("pubsubhubbub: subscriber did not echo back " . "hub.challenge, ignoring.");
            logger("\"{$hub_challenge}\" != \"" . trim($body) . "\"");
            http_status_exit(404);
        }
        // fetch the old subscription if it exists
        $r = 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'", dbesc($hub_callback));
        if ($subscribe) {
            $last_update = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
            $push_flag = 0;
            // if we are just updating an old subscription, keep the
            // old values for push and last_update
            if (count($r)) {
                $last_update = $r[0]['last_update'];
                $push_flag = $r[0]['push'];
            }
            // subscribe means adding the row to the table
            q("INSERT INTO `push_subscriber` (`uid`, `callback_url`, " . "`topic`, `nickname`, `push`, `last_update`, `secret`) values " . "(%d, '%s', '%s', '%s', %d, '%s', '%s')", intval($owner['uid']), dbesc($hub_callback), dbesc($hub_topic), dbesc($nick), intval($push_flag), 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();
}
Beispiel #28
0
/**
 *
 * diaspora_decode($importer,$xml,$format)
 *   array $importer -> from user table
 *   string $xml -> urldecoded Diaspora salmon
 *   string $format 'legacy', 'salmon', or 'json' 
 *
 * 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, $format)
{
    $public = false;
    if ($format === 'json') {
        $json = json_decode($xml, true);
        if ($json['aes_key']) {
            $key_bundle = '';
            $result = openssl_private_decrypt(base64_decode($json['aes_key']), $key_bundle, $importer['channel_prvkey']);
            if (!$result) {
                logger('decrypting key_bundle for ' . $importer['channel_address'] . ' failed: ' . $json['aes_key'], LOGGER_NORMAL, LOG_ERR);
                http_status_exit(400);
            }
            $jkey = json_decode($key_bundle, true);
            $xml = AES256CBC_decrypt(base64_decode($json['encrypted_magic_envelope']), base64_decode($jkey['key']), base64_decode($jkey['iv']));
            if (!$xml) {
                logger('decrypting magic_envelope for ' . $importer['channel_address'] . ' failed: ' . $json['aes_key'], LOGGER_NORMAL, LOG_ERR);
                http_status_exit(400);
            }
        }
    }
    $basedom = parse_xml_string($xml);
    if ($format !== 'legacy') {
        $children = $basedom->children('http://salmon-protocol.org/ns/magic-env');
        $public = true;
        $author_link = str_replace('acct:', '', base64url_decode($children->key_id));
        /**
        			SimpleXMLElement Object
        			(
        			    [encoding] => base64url
        			    [alg] => RSA-SHA256
        			    [data] => ((base64url-encoded payload message))
        			    [sig] => ((the RSA-SHA256 signature of the above data))
        			    [key_id] => ((base64url-encoded Alice's diaspora ID))
        			)
        		**/
    } else {
        $children = $basedom->children('https://joindiaspora.com/protocol');
        if ($children->header) {
            $public = true;
            $author_link = str_replace('acct:', '', $children->header->author_id);
        } else {
            $encrypted_header = json_decode(base64_decode($children->encrypted_header));
            $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
            $ciphertext = base64_decode($encrypted_header->ciphertext);
            $outer_key_bundle = '';
            openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $importer['channel_prvkey']);
            $j_outer_key_bundle = json_decode($outer_key_bundle);
            $outer_iv = base64_decode($j_outer_key_bundle->iv);
            $outer_key = base64_decode($j_outer_key_bundle->key);
            $decrypted = AES256CBC_decrypt($ciphertext, $outer_key, $outer_iv);
            /**
             * $decrypted now contains something like
             *
             *  <decrypted_header>
             *	 <iv>8e+G2+ET8l5BPuW0sVTnQw==</iv>
             *	 <aes_key>UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=</aes_key>
             ***** OBSOLETE
             *	 <author>
             *	   <name>Ryan Hughes</name>
             *	   <uri>acct:galaxor@diaspora.pirateship.org</uri>
             *	 </author>
             ***** CURRENT/LEGACY
             *	 <author_id>galaxor@diaspora.pirateship.org</author_id>
             ***** END DIFFS
             *  </decrypted_header>
             */
            logger('decrypted: ' . $decrypted, LOGGER_DATA);
            $idom = parse_xml_string($decrypted, false);
            $inner_iv = base64_decode($idom->iv);
            $inner_aes_key = base64_decode($idom->aes_key);
            $author_link = str_replace('acct:', '', $idom->author_id);
        }
    }
    $dom = $basedom->children(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-diaspora: unable to locate salmon data in xml ', LOGGER_NORMAL, LOG_ERR);
        http_status_exit(400);
    }
    // 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;
    $signed_data = $data . '.' . base64url_encode($type, false) . '.' . base64url_encode($encoding, false) . '.' . base64url_encode($alg, false);
    // decode the data
    $data = base64url_decode($data);
    if ($format === 'legacy' && !$public) {
        // Decode the encrypted blob
        $final_msg = AES256CBC_decrypt(base64_decode($data), $inner_aes_key, $inner_iv);
    } else {
        $final_msg = $data;
    }
    if (!$author_link) {
        logger('mod-diaspora: Could not retrieve author URI.');
        http_status_exit(400);
    }
    // Once we have the author URI, go to the web and try to find their public key
    // (first this will look it up locally if it is in the fcontact cache)
    // This will also convert diaspora public key from pkcs#1 to pkcs#8
    logger('mod-diaspora: Fetching key for ' . $author_link);
    $key = get_diaspora_key($author_link);
    if (!$key) {
        logger('mod-diaspora: Could not retrieve author key.', LOGGER_NORMAL, LOG_WARNING);
        http_status_exit(400);
    }
    $verify = rsa_verify($signed_data, $signature, $key);
    if (!$verify) {
        logger('mod-diaspora: Message did not verify. Discarding.', LOGGER_NORMAL, LOG_ERR);
        http_status_exit(400);
    }
    logger('mod-diaspora: Message verified.');
    return array('message' => $final_msg, 'author' => $author_link, 'key' => $key);
}
Beispiel #29
0
/**
 *
 * 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)
{
    $public = false;
    $basedom = parse_xml_string($xml);
    $children = $basedom->children('https://joindiaspora.com/protocol');
    if ($children->header) {
        $public = true;
        $author_link = str_replace('acct:', '', $children->header->author_id);
    } else {
        $encrypted_header = json_decode(base64_decode($children->encrypted_header));
        $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
        $ciphertext = base64_decode($encrypted_header->ciphertext);
        $outer_key_bundle = '';
        openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $importer['prvkey']);
        $j_outer_key_bundle = json_decode($outer_key_bundle);
        $outer_iv = base64_decode($j_outer_key_bundle->iv);
        $outer_key = base64_decode($j_outer_key_bundle->key);
        $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv);
        $decrypted = pkcs5_unpad($decrypted);
        /**
         * $decrypted now contains something like
         *
         *  <decrypted_header>
         *     <iv>8e+G2+ET8l5BPuW0sVTnQw==</iv>
         *     <aes_key>UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU=</aes_key>
         ***** OBSOLETE
         *     <author>
         *       <name>Ryan Hughes</name>
         *       <uri>acct:galaxor@diaspora.pirateship.org</uri>
         *     </author>
         ***** CURRENT
         *     <author_id>galaxor@diaspora.priateship.org</author_id>
         ***** END DIFFS
         *  </decrypted_header>
         */
        logger('decrypted: ' . $decrypted, LOGGER_DEBUG);
        $idom = parse_xml_string($decrypted, false);
        $inner_iv = base64_decode($idom->iv);
        $inner_aes_key = base64_decode($idom->aes_key);
        $author_link = str_replace('acct:', '', $idom->author_id);
    }
    $dom = $basedom->children(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-diaspora: unable to locate salmon data in xml ');
        http_status_exit(400);
    }
    // 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;
    $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
    // decode the data
    $data = base64url_decode($data);
    if ($public) {
        $inner_decrypted = $data;
    } else {
        // Decode the encrypted blob
        $inner_encrypted = base64_decode($data);
        $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv);
        $inner_decrypted = pkcs5_unpad($inner_decrypted);
    }
    if (!$author_link) {
        logger('mod-diaspora: Could not retrieve author URI.');
        http_status_exit(400);
    }
    // Once we have the author URI, go to the web and try to find their public key
    // (first this will look it up locally if it is in the fcontact cache)
    // This will also convert diaspora public key from pkcs#1 to pkcs#8
    logger('mod-diaspora: Fetching key for ' . $author_link);
    $key = get_diaspora_key($author_link);
    if (!$key) {
        logger('mod-diaspora: Could not retrieve author key.');
        http_status_exit(400);
    }
    $verify = rsa_verify($signed_data, $signature, $key);
    if (!$verify) {
        logger('mod-diaspora: Message did not verify. Discarding.');
        http_status_exit(400);
    }
    logger('mod-diaspora: Message verified.');
    return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key);
}
Beispiel #30
0
function salmon_post(&$a)
{
    $xml = file_get_contents('php://input');
    logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA);
    $nick = $a->argc > 1 ? notags(trim($a->argv[1])) : '';
    $mentions = $a->argc > 2 && $a->argv[2] === 'mention' ? true : false;
    $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nick));
    if (!count($r)) {
        http_status_exit(500);
    }
    $importer = $r[0];
    // 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);
    }
    // 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);
    // Remove the xml declaration
    $data = preg_replace('/\\<\\?xml[^\\?].*\\?\\>/', '', $data);
    // Create a fake feed wrapper so simplepie doesn't choke
    $tpl = get_markup_template('fake_feed.tpl');
    $base = substr($data, strpos($data, '<entry'));
    $feedxml = $tpl . $base . '</feed>';
    logger('mod-salmon: Processed feed: ' . $feedxml);
    // Now parse it like a normal atom feed to scrape out the author URI
    $feed = new SimplePie();
    $feed->set_raw_data($feedxml);
    $feed->enable_order_by_date(false);
    $feed->init();
    logger('mod-salmon: Feed parsed.');
    if ($feed->get_item_quantity()) {
        foreach ($feed->get_items() as $item) {
            $author = $item->get_author();
            $author_link = unxmlify($author->get_link());
            break;
        }
    }
    if (!$author_link) {
        logger('mod-salmon: Could not retrieve author URI.');
        http_status_exit(400);
    }
    // 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);
    $key = get_salmon_key($author_link, $keyhash);
    if (!$key) {
        logger('mod-salmon: Could not retrieve author key.');
        http_status_exit(400);
    }
    $key_info = explode('.', $key);
    $m = base64url_decode($key_info[1]);
    $e = base64url_decode($key_info[2]);
    logger('mod-salmon: key details: ' . print_r($key_info, true), LOGGER_DEBUG);
    $pubkey = metopem($m, $e);
    // We should have everything we need now. Let's see if it verifies.
    $verify = rsa_verify($compliant_format, $signature, $pubkey);
    if (!$verify) {
        logger('mod-salmon: message did not verify using protocol. Trying padding hack.');
        $verify = rsa_verify($signed_data, $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.');
    /*
     *
     * If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff.
     *
     */
    $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s' ) \n\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), dbesc($author_link), intval($importer['uid']));
    if (!count($r)) {
        logger('mod-salmon: Author unknown to us.');
        if (get_pconfig($importer['uid'], 'system', 'ostatus_autofriend')) {
            require_once 'include/follow.php';
            $result = new_contact($importer['uid'], $author_link);
            if ($result['success']) {
                $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s' ) \n\t\t\t\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), dbesc($author_link), intval($importer['uid']));
            }
        }
    }
    // is this a follower? Or have we ignored the person?
    // If so we can not accept this post.
    if (count($r) && ($r[0]['readonly'] || $r[0]['rel'] == CONTACT_IS_FOLLOWER || $r[0]['blocked'])) {
        logger('mod-salmon: Ignoring this author.');
        http_status_exit(202);
        // NOTREACHED
    }
    require_once 'include/items.php';
    // Placeholder for hub discovery. We shouldn't find any hubs
    // since we supplied the fake feed header - and it doesn't have any.
    $hub = '';
    /**
     *
     * anti-spam measure: consume_feed will accept a follow activity from 
     * this person (and nothing else) if there is no existing contact record.
     *
     */
    $contact_rec = count($r) ? $r[0] : null;
    consume_feed($feedxml, $importer, $contact_rec, $hub);
    http_status_exit(200);
}