Beispiel #1
0
function follow_post(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        goaway($_SESSION['return_url']);
        // NOTREACHED
    }
    if ($_REQUEST['cancel']) {
        goaway($_SESSION['return_url']);
    }
    $uid = local_user();
    $url = notags(trim($_REQUEST['url']));
    $return_url = $_SESSION['return_url'];
    // Makes the connection request for friendica contacts easier
    // This is just a precaution if maybe this page is called somewhere directly via POST
    $_SESSION["fastlane"] = $url;
    $result = new_contact($uid, $url, true);
    if ($result['success'] == false) {
        if ($result['message']) {
            notice($result['message']);
        }
        goaway($return_url);
    } elseif ($result['cid']) {
        goaway($a->get_baseurl() . '/contacts/' . $result['cid']);
    }
    info(t('Contact added') . EOL);
    if (strstr($return_url, 'contacts')) {
        goaway($a->get_baseurl() . '/contacts/' . $contact_id);
    }
    goaway($return_url);
    // NOTREACHED
}
function repair_ostatus_content(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        goaway($_SESSION['return_url']);
        // NOTREACHED
    }
    $o = "<h2>" . t("Resubsribing to OStatus contacts") . "</h2>";
    $uid = local_user();
    $a = get_app();
    $counter = intval($_REQUEST['counter']);
    $r = q("SELECT COUNT(*) AS `total` FROM `contact` WHERE\n                `uid` = %d AND `network` = '%s' AND `rel` IN (%d, %d)", intval($uid), dbesc(NETWORK_OSTATUS), intval(CONTACT_IS_FRIEND), intval(CONTACT_IS_SHARING));
    if (!$r) {
        return $o . t("Error");
    }
    $total = $r[0]["total"];
    $r = q("SELECT `url` FROM `contact` WHERE\n                `uid` = %d AND `network` = '%s' AND `rel` IN (%d, %d)\n\t\tORDER BY `url`\n\t\tLIMIT %d, 1", intval($uid), dbesc(NETWORK_OSTATUS), intval(CONTACT_IS_FRIEND), intval(CONTACT_IS_SHARING), $counter++);
    if (!$r) {
        $o .= t("Done");
        return $o;
    }
    $o .= "<p>" . $counter . "/" . $total . ": " . $r[0]["url"] . "</p>";
    $o .= "<p>" . t("Keep this window open until done.") . "</p>";
    $result = new_contact($uid, $r[0]["url"], true);
    $a->page['htmlhead'] = '<meta http-equiv="refresh" content="1; URL=' . $a->get_baseurl() . '/repair_ostatus?counter=' . $counter . '">';
    return $o;
}
Beispiel #3
0
function ostatus_follow_friends($uid, $url)
{
    $contact = probe_url($url);
    if (!$contact) {
        return;
    }
    $api = $contact["baseurl"] . "/api/";
    // Fetching friends
    $data = z_fetch_url($api . "statuses/friends.json?screen_name=" . $contact["nick"]);
    if (!$data["success"]) {
        return;
    }
    $friends = json_decode($data["body"]);
    foreach ($friends as $friend) {
        $url = $friend->statusnet_profile_url;
        $r = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND\n\t\t\t(`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s') AND\n\t\t\t`network` != '%s' LIMIT 1", intval($uid), dbesc(normalise_link($url)), dbesc(normalise_link($url)), dbesc($url), dbesc(NETWORK_STATUSNET));
        if (!$r) {
            $data = probe_url($friend->statusnet_profile_url);
            if ($data["network"] == NETWORK_OSTATUS) {
                $result = new_contact($uid, $friend->statusnet_profile_url);
                if ($result["success"]) {
                    logger($friend->name . " " . $url . " - success", LOGGER_DEBUG);
                } else {
                    logger($friend->name . " " . $url . " - failed", LOGGER_DEBUG);
                }
            } else {
                logger($friend->name . " " . $url . " - not OStatus", LOGGER_DEBUG);
            }
        }
    }
}
Beispiel #4
0
function follow_init(&$a)
{
    if (!local_channel()) {
        return;
    }
    $uid = local_channel();
    $url = notags(trim($_REQUEST['url']));
    $return_url = $_SESSION['return_url'];
    $confirm = intval($_REQUEST['confirm']);
    $result = new_contact($uid, $url, $a->get_channel(), true, $confirm);
    if ($result['success'] == false) {
        if ($result['message']) {
            notice($result['message']);
        }
        goaway($return_url);
    }
    info(t('Channel added.') . EOL);
    $clone = array();
    foreach ($result['abook'] as $k => $v) {
        if (strpos($k, 'abook_') === 0) {
            $clone[$k] = $v;
        }
    }
    unset($clone['abook_id']);
    unset($clone['abook_account']);
    unset($clone['abook_channel']);
    build_sync_packet(0, array('abook' => array($clone)));
    // If we can view their stream, pull in some posts
    if ($result['abook']['abook_their_perms'] & PERMS_R_STREAM || $result['abook']['xchan_network'] === 'rss') {
        proc_run('php', 'include/onepoll.php', $result['abook']['abook_id']);
    }
    goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
}
function ostatus_subscribe_content(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        goaway($_SESSION['return_url']);
        // NOTREACHED
    }
    $o = "<h2>" . t("Subsribing to OStatus contacts") . "</h2>";
    $uid = local_user();
    $a = get_app();
    $counter = intval($_REQUEST['counter']);
    if (get_pconfig($uid, "ostatus", "legacy_friends") == "") {
        if ($_REQUEST["url"] == "") {
            return $o . t("No contact provided.");
        }
        $contact = probe_url($_REQUEST["url"]);
        if (!$contact) {
            return $o . t("Couldn't fetch information for contact.");
        }
        $api = $contact["baseurl"] . "/api/";
        // Fetching friends
        $data = z_fetch_url($api . "statuses/friends.json?screen_name=" . $contact["nick"]);
        if (!$data["success"]) {
            return $o . t("Couldn't fetch friends for contact.");
        }
        set_pconfig($uid, "ostatus", "legacy_friends", $data["body"]);
    }
    $friends = json_decode(get_pconfig($uid, "ostatus", "legacy_friends"));
    $total = sizeof($friends);
    if ($counter >= $total) {
        $a->page['htmlhead'] = '<meta http-equiv="refresh" content="0; URL=' . $a->get_baseurl() . '/settings/connectors">';
        del_pconfig($uid, "ostatus", "legacy_friends");
        del_pconfig($uid, "ostatus", "legacy_contact");
        $o .= t("Done");
        return $o;
    }
    $friend = $friends[$counter++];
    $url = $friend->statusnet_profile_url;
    $o .= "<p>" . $counter . "/" . $total . ": " . $url;
    $data = probe_url($url);
    if ($data["network"] == NETWORK_OSTATUS) {
        $result = new_contact($uid, $url, true);
        if ($result["success"]) {
            $o .= " - " . t("success");
        } else {
            $o .= " - " . t("failed");
        }
    } else {
        $o .= " - " . t("ignored");
    }
    $o .= "</p>";
    $o .= "<p>" . t("Keep this window open until done.") . "</p>";
    $a->page['htmlhead'] = '<meta http-equiv="refresh" content="0; URL=' . $a->get_baseurl() . '/ostatus_subscribe?counter=' . $counter . '">';
    return $o;
}
Beispiel #6
0
 function init()
 {
     if (!local_channel()) {
         return;
     }
     $uid = local_channel();
     $url = notags(trim($_REQUEST['url']));
     $return_url = $_SESSION['return_url'];
     $confirm = intval($_REQUEST['confirm']);
     $channel = \App::get_channel();
     // Warning: Do not edit the following line. The first symbol is UTF-8 &#65312;
     $url = str_replace('@', '@', $url);
     $result = new_contact($uid, $url, $channel, true, $confirm);
     if ($result['success'] == false) {
         if ($result['message']) {
             notice($result['message']);
         }
         goaway($return_url);
     }
     info(t('Channel added.') . EOL);
     $clone = array();
     foreach ($result['abook'] as $k => $v) {
         if (strpos($k, 'abook_') === 0) {
             $clone[$k] = $v;
         }
     }
     unset($clone['abook_id']);
     unset($clone['abook_account']);
     unset($clone['abook_channel']);
     $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']);
     if ($abconfig) {
         $clone['abconfig'] = $abconfig;
     }
     build_sync_packet(0, array('abook' => array($clone)), true);
     $can_view_stream = intval(get_abconfig($channel['channel_id'], $clone['abook_xchan'], 'their_perms', 'view_stream'));
     // If we can view their stream, pull in some posts
     if ($can_view_stream || $result['abook']['xchan_network'] === 'rss') {
         \Zotlabs\Daemon\Master::Summon(array('Onepoll', $result['abook']['abook_id']));
     }
     goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
 }
Beispiel #7
0
function follow_init(&$a)
{
    if (!local_channel()) {
        return;
    }
    $uid = local_channel();
    $url = notags(trim($_REQUEST['url']));
    $return_url = $_SESSION['return_url'];
    $confirm = intval($_REQUEST['confirm']);
    $result = new_contact($uid, $url, $a->get_channel(), true, $confirm);
    if ($result['success'] == false) {
        if ($result['message']) {
            notice($result['message']);
        }
        goaway($return_url);
    }
    info(t('Channel added.') . EOL);
    // If we can view their stream, pull in some posts
    if ($result['abook']['abook_their_perms'] & PERMS_R_STREAM || $result['abook']['xchan_network'] === 'rss') {
        proc_run('php', 'include/onepoll.php', $result['abook']['abook_id']);
    }
    goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
}
Beispiel #8
0
function follow_init(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        goaway($_SESSION['return_url']);
        // NOTREACHED
    }
    $uid = local_user();
    $url = notags(trim($_REQUEST['url']));
    $return_url = $_SESSION['return_url'];
    $result = new_contact($uid, $url, true);
    if ($result['success'] == false) {
        if ($result['message']) {
            notice($result['message']);
        }
        goaway($return_url);
    }
    info(t('Contact added') . EOL);
    if (strstr($return_url, 'contacts')) {
        goaway($a->get_baseurl() . '/contacts/' . $contact_id);
    }
    goaway($return_url);
    // NOTREACHED
}
Beispiel #9
0
/**
 * @brief Create a new channel.
 *
 * Also creates the related xchan, hubloc, profile, and "self" abook records,
 * and an empty "Friends" group/collection for the new channel.
 *
 * @param array $arr assoziative array with:
 *  * \e string \b name full name of channel
 *  * \e string \b nickname "email/url-compliant" nickname
 *  * \e int \b account_id to attach with this channel
 *  * [other identity fields as desired]
 *
 * @returns array
 *     'success' => boolean true or false
 *     'message' => optional error text if success is false
 *     'channel' => if successful the created channel array
 */
function create_identity($arr)
{
    $a = get_app();
    $ret = array('success' => false);
    if (!$arr['account_id']) {
        $ret['message'] = t('No account identifier');
        return $ret;
    }
    $ret = identity_check_service_class($arr['account_id']);
    if (!$ret['success']) {
        return $ret;
    }
    // save this for auto_friending
    $total_identities = $ret['total_identities'];
    $nick = mb_strtolower(trim($arr['nickname']));
    if (!$nick) {
        $ret['message'] = t('Nickname is required.');
        return $ret;
    }
    $name = escape_tags($arr['name']);
    $pageflags = x($arr, 'pageflags') ? intval($arr['pageflags']) : PAGE_NORMAL;
    $system = x($arr, 'system') ? intval($arr['system']) : 0;
    $name_error = validate_channelname($arr['name']);
    if ($name_error) {
        $ret['message'] = $name_error;
        return $ret;
    }
    if ($nick === 'sys' && !$system) {
        $ret['message'] = t('Reserved nickname. Please choose another.');
        return $ret;
    }
    if (check_webbie(array($nick)) !== $nick) {
        $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
        return $ret;
    }
    $guid = zot_new_uid($nick);
    $key = new_keypair(4096);
    $sig = base64url_encode(rsa_sign($guid, $key['prvkey']));
    $hash = make_xchan_hash($guid, $sig);
    // Force a few things on the short term until we can provide a theme or app with choice
    $publish = 1;
    if (array_key_exists('publish', $arr)) {
        $publish = intval($arr['publish']);
    }
    $primary = true;
    if (array_key_exists('primary', $arr)) {
        $primary = intval($arr['primary']);
    }
    $role_permissions = null;
    $global_perms = get_perms();
    if (array_key_exists('permissions_role', $arr) && $arr['permissions_role']) {
        $role_permissions = get_role_perms($arr['permissions_role']);
        if ($role_permissions) {
            foreach ($role_permissions as $p => $v) {
                if (strpos($p, 'channel_') !== false) {
                    $perms_keys .= ', ' . $p;
                    $perms_vals .= ', ' . intval($v);
                }
                if ($p === 'directory_publish') {
                    $publish = intval($v);
                }
            }
        }
    } else {
        $defperms = site_default_perms();
        foreach ($defperms as $p => $v) {
            $perms_keys .= ', ' . $global_perms[$p][0];
            $perms_vals .= ', ' . intval($v);
        }
    }
    $expire = 0;
    $r = q("insert into channel ( channel_account_id, channel_primary, \n\t\tchannel_name, channel_address, channel_guid, channel_guid_sig,\n\t\tchannel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_system, channel_expire_days, channel_timezone {$perms_keys} )\n\t\tvalues ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s' {$perms_vals} ) ", intval($arr['account_id']), intval($primary), dbesc($name), dbesc($nick), dbesc($guid), dbesc($sig), dbesc($hash), dbesc($key['prvkey']), dbesc($key['pubkey']), intval($pageflags), intval($system), intval($expire), dbesc($a->timezone));
    $r = q("select * from channel where channel_account_id = %d \n\t\tand channel_guid = '%s' limit 1", intval($arr['account_id']), dbesc($guid));
    if (!$r) {
        $ret['message'] = t('Unable to retrieve created identity');
        return $ret;
    }
    $ret['channel'] = $r[0];
    if (intval($arr['account_id'])) {
        set_default_login_identity($arr['account_id'], $ret['channel']['channel_id'], false);
    }
    // Create a verified hub location pointing to this site.
    $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, \n\t\thubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network )\n\t\tvalues ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($guid), dbesc($sig), dbesc($hash), dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $ret['channel']['channel_prvkey']))), dbesc(get_app()->get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system', 'pubkey')), dbesc('zot'));
    if (!$r) {
        logger('create_identity: Unable to store hub location');
    }
    $newuid = $ret['channel']['channel_id'];
    $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_system ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", dbesc($hash), dbesc($guid), dbesc($sig), dbesc($key['pubkey']), dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/s/{$newuid}"), dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), dbesc(z_root() . '/channel/' . $ret['channel']['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $ret['channel']['channel_address']), dbesc($ret['channel']['channel_name']), dbesc('zot'), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($system));
    // Not checking return value.
    // It's ok for this to fail if it's an imported channel, and therefore the hash is a duplicate
    $r = q("INSERT INTO profile ( aid, uid, profile_guid, profile_name, is_default, publish, name, photo, thumb)\n\t\tVALUES ( %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s') ", intval($ret['channel']['channel_account_id']), intval($newuid), dbesc(random_string()), t('Default Profile'), 1, $publish, dbesc($ret['channel']['channel_name']), dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"));
    if ($role_permissions) {
        $myperms = array_key_exists('perms_auto', $role_permissions) && $role_permissions['perms_auto'] ? intval($role_permissions['perms_accept']) : 0;
    } else {
        $myperms = PERMS_R_STREAM | PERMS_R_PROFILE | PERMS_R_PHOTOS | PERMS_R_ABOOK | PERMS_W_STREAM | PERMS_W_WALL | PERMS_W_COMMENT | PERMS_W_MAIL | PERMS_W_CHAT | PERMS_R_STORAGE | PERMS_R_PAGES | PERMS_W_LIKE;
    }
    $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_self, abook_my_perms )\n\t\tvalues ( %d, %d, '%s', %d, '%s', '%s', %d, %d ) ", intval($ret['channel']['channel_account_id']), intval($newuid), dbesc($hash), intval(0), dbesc(datetime_convert()), dbesc(datetime_convert()), intval(1), intval($myperms));
    if (intval($ret['channel']['channel_account_id'])) {
        // Save our permissions role so we can perhaps call it up and modify it later.
        if ($role_permissions) {
            set_pconfig($newuid, 'system', 'permissions_role', $arr['permissions_role']);
            if (array_key_exists('online', $role_permissions)) {
                set_pconfig($newuid, 'system', 'hide_presence', 1 - intval($role_permissions['online']));
            }
            if (array_key_exists('perms_auto', $role_permissions)) {
                set_pconfig($newuid, 'system', 'autoperms', $role_permissions['perms_auto'] ? $role_permissions['perms_accept'] : 0);
            }
        }
        // Create a group with yourself as a member. This allows somebody to use it
        // right away as a default group for new contacts.
        require_once 'include/group.php';
        group_add($newuid, t('Friends'));
        group_add_member($newuid, t('Friends'), $ret['channel']['channel_hash']);
        // if our role_permissions indicate that we're using a default collection ACL, add it.
        if (is_array($role_permissions) && $role_permissions['default_collection']) {
            $r = q("select hash from groups where uid = %d and name = '%s' limit 1", intval($newuid), dbesc(t('Friends')));
            if ($r) {
                q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d", dbesc($r[0]['hash']), dbesc('<' . $r[0]['hash'] . '>'), intval($newuid));
            }
        }
        if (!$system) {
            set_pconfig($ret['channel']['channel_id'], 'system', 'photo_path', '%Y-%m');
            set_pconfig($ret['channel']['channel_id'], 'system', 'attach_path', '%Y-%m');
        }
        // auto-follow any of the hub's pre-configured channel choices.
        // Only do this if it's the first channel for this account;
        // otherwise it could get annoying. Don't make this list too big
        // or it will impact registration time.
        $accts = get_config('system', 'auto_follow');
        if ($accts && !$total_identities) {
            require_once 'include/follow.php';
            if (!is_array($accts)) {
                $accts = array($accts);
            }
            foreach ($accts as $acct) {
                if (trim($acct)) {
                    new_contact($newuid, trim($acct), $ret['channel'], false);
                }
            }
        }
        call_hooks('create_identity', $newuid);
        proc_run('php', 'include/directory.php', $ret['channel']['channel_id']);
    }
    $ret['success'] = true;
    return $ret;
}
Beispiel #10
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 #11
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);
}
Beispiel #12
0
function import_diaspora($data)
{
    $a = get_app();
    $account = $a->get_account();
    if (!$account) {
        return false;
    }
    $address = escape_tags($data['user']['username']);
    if (!$address) {
        notice(t('No username found in import file.') . EOL);
        return false;
    }
    $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($address));
    if ($r) {
        // try at most ten times to generate a unique address.
        $x = 0;
        $found_unique = false;
        do {
            $tmp = $address . mt_rand(1000, 9999);
            $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($tmp));
            if (!$r) {
                $address = $tmp;
                $found_unique = true;
                break;
            }
            $x++;
        } while ($x < 10);
        if (!$found_unique) {
            logger('import_diaspora: duplicate channel address. randomisation failed.');
            notice(t('Unable to create a unique channel address. Import failed.') . EOL);
            return;
        }
    }
    $c = create_identity(array('name' => escape_tags($data['user']['name']), 'nickname' => $address, 'account_id' => $account['account_id'], 'permissions_role' => 'social'));
    if (!$c['success']) {
        return;
    }
    $channel_id = $c['channel']['channel_id'];
    // todo - add auto follow settings, (and strip exif in hubzilla)
    $location = escape_tags($data['user']['profile']['location']);
    if (!$location) {
        $location = '';
    }
    q("update channel set channel_location = '%s' where channel_id = %d", dbesc($location), intval($channel_id));
    if ($data['user']['profile']['nsfw']) {
        // fixme for hubzilla which doesn't use pageflags any more
        q("update channel set channel_pageflags = (channel_pageflags | %d) where channel_id = %d", intval(PAGE_ADULT), intval($channel_id));
    }
    if ($data['user']['profile']['image_url']) {
        $p = z_fetch_url($data['user']['profile']['image_url'], true);
        if ($p['success']) {
            $rawbytes = $p['body'];
            $type = guess_image_type('dummyfile', $p['header']);
            import_channel_photo($rawbytes, $type, $c['channel']['channel_account_id'], $channel_id);
        }
    }
    $gender = escape_tags($data['user']['profile']['gender']);
    $about = diaspora2bb($data['user']['profile']['bio']);
    $publish = intval($data['user']['profile']['searchable']);
    if ($data['user']['profile']['birthday']) {
        $dob = datetime_convert('UTC', 'UTC', $data['user']['profile']['birthday'], 'Y-m-d');
    } else {
        $dob = '0000-00-00';
    }
    // we're relying on the fact that this channel was just created and will only
    // have the default profile currently
    $r = q("update profile set gender = '%s', about = '%s', dob = '%s', publish = %d where uid = %d", dbesc($gender), dbesc($about), dbesc($dob), dbesc($publish), intval($channel_id));
    if ($data['user']['aspects']) {
        foreach ($data['user']['aspects'] as $aspect) {
            group_add($channel_id, escape_tags($aspect['name']), intval($aspect['contacts_visible']));
        }
    }
    // now add connections and send friend requests
    if ($data['user']['contacts']) {
        foreach ($data['user']['contacts'] as $contact) {
            $result = new_contact($channel_id, $contact['person_diaspora_handle'], $c['channel']);
            if ($result['success']) {
                if ($contact['aspects']) {
                    foreach ($contact['aspects'] as $aspect) {
                        group_add_member($channel_id, $aspect['name'], $result['abook']['xchan_hash']);
                    }
                }
            }
        }
    }
    // Then add items - note this can't be done until Diaspora adds guids to exported
    // items and comments
    // This will indirectly perform a refresh_all *and* update the directory
    proc_run('php', 'include/directory.php', $channel_id);
    notice(t('Import completed.') . EOL);
    change_channel($channel_id);
    goaway(z_root() . '/network');
}
Beispiel #13
0
function _contact_update_profile($contact_id)
{
    $r = q("SELECT `uid`, `url`, `network` FROM `contact` WHERE `id` = %d", intval($contact_id));
    if (!$r) {
        return;
    }
    $uid = $r[0]["uid"];
    if ($uid != local_user()) {
        return;
    }
    $data = probe_url($r[0]["url"]);
    // "Feed" is mostly a sign of communication problems
    if ($data["network"] == NETWORK_FEED and $data["network"] != $r[0]["network"]) {
        return;
    }
    $updatefields = array("name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm", "poco", "network", "alias", "pubkey");
    $update = array();
    if ($data["network"] == NETWORK_OSTATUS) {
        $result = new_contact($uid, $data["url"], false);
        if ($result['success']) {
            $update["subhub"] = true;
        }
    }
    foreach ($updatefields as $field) {
        if (isset($data[$field]) and $data[$field] != "") {
            $update[$field] = $data[$field];
        }
    }
    $update["nurl"] = normalise_link($data["url"]);
    $query = "";
    if (isset($data["priority"]) and $data["priority"] != 0) {
        $query = "`priority` = " . intval($data["priority"]);
    }
    foreach ($update as $key => $value) {
        if ($query != "") {
            $query .= ", ";
        }
        $query .= "`" . $key . "` = '" . dbesc($value) . "'";
    }
    if ($query == "") {
        return;
    }
    $r = q("UPDATE `contact` SET {$query} WHERE `id` = %d AND `uid` = %d", intval($contact_id), intval(local_user()));
    $photos = import_profile_photo($data['photo'], local_user(), $contact_id);
    $r = q("UPDATE `contact` SET `photo` = '%s',\n\t\t\t`thumb` = '%s',\n\t\t\t`micro` = '%s',\n\t\t\t`name-date` = '%s',\n\t\t\t`uri-date` = '%s',\n\t\t\t`avatar-date` = '%s'\n\t\t\tWHERE `id` = %d", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($contact_id));
}