コード例 #1
0
function dfrn_poll_init(&$a)
{
    $dfrn_id = '';
    if (x($_GET, 'dfrn_id')) {
        $dfrn_id = $a->config['dfrn_poll_dfrn_id'] = $_GET['dfrn_id'];
    }
    if (x($_GET, 'type')) {
        $type = $a->config['dfrn_poll_type'] = $_GET['type'];
    }
    if (x($_GET, 'last_update')) {
        $last_update = $a->config['dfrn_poll_last_update'] = $_GET['last_update'];
    }
    $dfrn_version = x($_GET, 'dfrn_version') ? $_GET['dfrn_version'] : '1.0';
    $destination_url = x($_GET, 'destination_url') ? $_GET['destination_url'] : '';
    if ($dfrn_id == '' && !x($_POST, 'dfrn_id') && $a->argc > 1) {
        $o = get_feed_for($a, '*', $a->argv[1], $last_update);
        echo $o;
        killme();
    }
    if (x($type) && $type == 'profile') {
        $r = q("SELECT `contact`.*, `user`.`nickname` \n\t\t\tFROM `contact` LEFT JOIN `user` ON `user`.`uid` = 1\n\t\t\tWHERE ( `dfrn-id` = '%s' OR ( `issued-id` = '%s' AND `duplex` = 1 )) LIMIT 1", dbesc($dfrn_id), dbesc($dfrn_id));
        if (count($r)) {
            $s = fetch_url($r[0]['poll'] . '?dfrn_id=' . $dfrn_id . '&type=profile-check');
            if (strlen($s)) {
                $xml = simplexml_load_string($s);
                if ((int) $xml->status == 1) {
                    $_SESSION['authenticated'] = 1;
                    $_SESSION['visitor_id'] = $r[0]['id'];
                    notice(t('Hi ') . $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' LIMIT 1", dbesc($expire), dbesc($session_id));
                }
            }
            $profile = $r[0]['nickname'];
            goaway(strlen($destination_url) ? $destination_url : $a->get_baseurl() . '/profile/' . $profile);
        }
        goaway($a->get_baseurl());
    }
    if (x($type) && $type == 'profile-check') {
        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
    }
}
コード例 #2
0
ファイル: ping.php プロジェクト: vishalp/MistparkPE-Remix
function ping_init(&$a)
{
    if (!local_user()) {
        xml_status(0);
    }
    $r = q("SELECT COUNT(*) AS `total` FROM `item` \n\t\tWHERE `unseen` = 1 AND `visible` = 1 AND `deleted` = 0 ");
    $network = $r[0]['total'];
    $r = q("SELECT COUNT(*) AS `total` FROM `item` \n\t\tWHERE `unseen` = 1 AND `visible` = 1 AND `deleted` = 0 AND `type` != 'remote' ");
    $home = $r[0]['total'];
    $r = q("SELECT COUNT(*) AS `total` FROM `intro` \n\t\tWHERE `blocked` = 0 AND `ignore` = 0 ");
    $intro = $r[0]['total'];
    $myurl = $a->get_baseurl() . '/profile/' . $user['nickname'];
    $r = q("SELECT COUNT(*) AS `total` FROM `mail`\n\t\tWHERE `seen` = 0 AND `from-url` != '%s' ", dbesc($myurl));
    $mail = $r[0]['total'];
    header("Content-type: text/xml");
    echo "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n<result><intro>{$intro}</intro><mail>{$mail}</mail><net>{$network}</net><home>{$home}</home></result>\r\n";
    killme();
}
コード例 #3
0
ファイル: dfrn_poll.php プロジェクト: nphyx/friendica
function dfrn_poll_post(&$a)
{
    $dfrn_id = x($_POST, 'dfrn_id') ? $_POST['dfrn_id'] : '';
    $challenge = x($_POST, 'challenge') ? $_POST['challenge'] : '';
    $url = x($_POST, 'url') ? $_POST['url'] : '';
    $sec = x($_POST, 'sec') ? $_POST['sec'] : '';
    $ptype = x($_POST, 'type') ? $_POST['type'] : '';
    $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
    $perm = x($_POST, 'perm') ? $_POST['perm'] : 'r';
    if ($ptype === 'profile-check') {
        if (strlen($challenge) && strlen($sec)) {
            logger('dfrn_poll: POST: profile-check');
            q("DELETE FROM `profile_check` WHERE `expire` < " . intval(time()));
            $r = q("SELECT * FROM `profile_check` WHERE `sec` = '%s' ORDER BY `expire` DESC LIMIT 1", dbesc($sec));
            if (!count($r)) {
                xml_status(3, 'No ticket');
                // NOTREACHED
            }
            $orig_id = $r[0]['dfrn_id'];
            if (strpos($orig_id, ':')) {
                $orig_id = substr($orig_id, 2);
            }
            $c = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($r[0]['cid']));
            if (!count($c)) {
                xml_status(3, 'No profile');
            }
            $contact = $c[0];
            $sent_dfrn_id = hex2bin($dfrn_id);
            $challenge = hex2bin($challenge);
            $final_dfrn_id = '';
            if ($contact['duplex'] && strlen($contact['prvkey'])) {
                openssl_private_decrypt($sent_dfrn_id, $final_dfrn_id, $contact['prvkey']);
                openssl_private_decrypt($challenge, $decoded_challenge, $contact['prvkey']);
            } else {
                openssl_public_decrypt($sent_dfrn_id, $final_dfrn_id, $contact['pubkey']);
                openssl_public_decrypt($challenge, $decoded_challenge, $contact['pubkey']);
            }
            $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.'));
            if (strpos($final_dfrn_id, ':') == 1) {
                $final_dfrn_id = substr($final_dfrn_id, 2);
            }
            if ($final_dfrn_id != $orig_id) {
                logger('profile_check: ' . $final_dfrn_id . ' != ' . $orig_id, LOGGER_DEBUG);
                // did not decode properly - cannot trust this site
                xml_status(3, 'Bad decryption');
            }
            header("Content-type: text/xml");
            echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dfrn_poll><status>0</status><challenge>{$decoded_challenge}</challenge><sec>{$sec}</sec></dfrn_poll>";
            killme();
            // NOTREACHED
        }
    }
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        killme();
    }
    $type = $r[0]['type'];
    $last_update = $r[0]['last_update'];
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    $sql_extra = '';
    switch ($direction) {
        case -1:
            $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id));
            $my_id = $dfrn_id;
            break;
        case 0:
            $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            $my_id = '1:' . $dfrn_id;
            break;
        case 1:
            $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            $my_id = '0:' . $dfrn_id;
            break;
        default:
            goaway(z_root());
            break;
            // NOTREACHED
    }
    $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 {$sql_extra} LIMIT 1");
    if (!count($r)) {
        killme();
    }
    $contact = $r[0];
    $owner_uid = $r[0]['uid'];
    $contact_id = $r[0]['id'];
    if ($type === 'reputation' && strlen($url)) {
        $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($url), intval($owner_uid));
        $reputation = 0;
        $text = '';
        if (count($r)) {
            $reputation = $r[0]['rating'];
            $text = $r[0]['reason'];
            if ($r[0]['id'] == $contact_id) {
                // inquiring about own reputation not allowed
                $reputation = 0;
                $text = '';
            }
        }
        echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t<reputation>\n\t\t\t<url>{$url}</url>\n\t\t\t<rating>{$reputation}</rating>\n\t\t\t<description>{$text}</description>\n\t\t</reputation>\n\t\t";
        killme();
        // NOTREACHED
    } else {
        // Update the writable flag if it changed
        logger('dfrn_poll: post request feed: ' . print_r($_POST, true), LOGGER_DATA);
        if ($dfrn_version >= 2.21) {
            if ($perm === 'rw') {
                $writable = 1;
            } else {
                $writable = 0;
            }
            if ($writable != $contact['writable']) {
                q("UPDATE `contact` SET `writable` = %d WHERE `id` = %d LIMIT 1", intval($writable), intval($contact_id));
            }
        }
        header("Content-type: application/atom+xml");
        $o = get_feed_for($a, $dfrn_id, $a->argv[1], $last_update, $direction);
        echo $o;
        killme();
    }
}
コード例 #4
0
ファイル: dfrn_notify.php プロジェクト: robhell/friendica
function dfrn_notify_post(&$a)
{
    $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : '';
    $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
    $challenge = x($_POST, 'challenge') ? notags(trim($_POST['challenge'])) : '';
    $data = x($_POST, 'data') ? $_POST['data'] : '';
    $key = x($_POST, 'key') ? $_POST['key'] : '';
    $dissolve = x($_POST, 'dissolve') ? intval($_POST['dissolve']) : 0;
    $perm = x($_POST, 'perm') ? notags(trim($_POST['perm'])) : 'r';
    $ssl_policy = x($_POST, 'ssl_policy') ? notags(trim($_POST['ssl_policy'])) : 'none';
    $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
    $forum = $page == 1 ? 1 : 0;
    $prv = $page == 2 ? 1 : 0;
    $writable = -1;
    if ($dfrn_version >= 2.21) {
        $writable = $perm === 'rw' ? 1 : 0;
    }
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
        xml_status(3);
    }
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    // find the local user who owns this relationship.
    $sql_extra = '';
    switch ($direction) {
        case -1:
            $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
            break;
        case 0:
            $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        case 1:
            $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        default:
            xml_status(3);
            break;
            // NOTREACHED
    }
    // be careful - $importer will contain both the contact information for the contact
    // sending us the post, and also the user information for the person receiving it.
    // since they are mixed together, it is easy to get them confused.
    $r = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`, \n\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`, \n\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`, \n\t\t\t\t\t`contact`.`thumb` AS `thumb`, \n\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t`user`.* \n\t\t\tFROM `contact` \n\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` \n\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 \n\t\t\t\tAND `user`.`nickname` = '%s' AND `user`.`account_expired` = 0 {$sql_extra} LIMIT 1", dbesc($a->argv[1]));
    if (!count($r)) {
        logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id);
        xml_status(3);
        //NOTREACHED
    }
    // $importer in this case contains the contact record for the remote contact joined with the user record of our user.
    $importer = $r[0];
    if ($writable != -1 && $writable != $importer['writable'] || $importer['forum'] != $forum || $importer['prv'] != $prv) {
        q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d LIMIT 1", intval($writable == -1 ? $importer['writable'] : $writable), intval($forum), intval($prv), intval($importer['id']));
        if ($writable != -1) {
            $importer['writable'] = $writable;
        }
        $importer['forum'] = $page;
    }
    // if contact's ssl policy changed, update our links
    fix_contact_ssl_policy($importer, $ssl_policy);
    logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']);
    logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
    if ($dissolve == 1) {
        /**
         * Relationship is dissolved permanently
         */
        require_once 'include/Contact.php';
        contact_remove($importer['id']);
        logger('relationship dissolved : ' . $importer['name'] . ' dissolved ' . $importer['username']);
        xml_status(0);
    }
    // If we are setup as a soapbox we aren't accepting input from this person
    if ($importer['page-flags'] == PAGE_SOAPBOX) {
        xml_status(0);
    }
    if (strlen($key)) {
        $rawkey = hex2bin(trim($key));
        logger('rino: md5 raw key: ' . md5($rawkey));
        $final_key = '';
        if ($dfrn_version >= 2.1) {
            if ($importer['duplex'] && strlen($importer['cprvkey']) || !strlen($importer['cpubkey'])) {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            } else {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            }
        } else {
            if ($importer['duplex'] && strlen($importer['cpubkey']) || !strlen($importer['cprvkey'])) {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            } else {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            }
        }
        logger('rino: received key : ' . $final_key);
        $data = aes_decrypt(hex2bin($data), $final_key);
        logger('rino: decrypted data: ' . $data, LOGGER_DATA);
    }
    $ret = local_delivery($importer, $data);
    xml_status($ret);
    // NOTREACHED
}
コード例 #5
0
function dfrn_notify_post(&$a)
{
    $dfrn_id = notags(trim($_POST['dfrn_id']));
    $challenge = notags(trim($_POST['challenge']));
    $data = $_POST['data'];
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        xml_status(3);
    }
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    // find the local user who owns this relationship.
    $r = q("SELECT `contact`.*, `user`.* FROM `contact` LEFT JOIN `user` on `user`.`uid` = 1 \n\t\tWHERE ( `issued-id` = '%s' OR ( `duplex` = 1 AND `dfrn-id` = '%s' )) LIMIT 1", dbesc($dfrn_id), dbesc($dfrn_id));
    if (!count($r)) {
        xml_status(3);
        return;
        //NOTREACHED
    }
    $importer = $r[0];
    $feed = new SimplePie();
    $feed->set_raw_data($data);
    $feed->enable_order_by_date(false);
    $feed->init();
    $ismail = false;
    $rawmail = $feed->get_feed_tags(NAMESPACE_DFRN, 'mail');
    if (isset($rawmail[0]['child'][NAMESPACE_DFRN])) {
        if ($importer['readonly']) {
            // We aren't receiving email from this person. But we will quietly ignore them
            // rather than a blatant "go away" message.
            xml_status(0);
            return;
            //NOTREACHED
        }
        $ismail = true;
        $base = $rawmail[0]['child'][NAMESPACE_DFRN];
        $msg = array();
        $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data']));
        $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data']));
        $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data']));
        $msg['contact-id'] = $importer['id'];
        $msg['title'] = notags(unxmlify($base['subject'][0]['data']));
        $msg['body'] = escape_tags(unxmlify($base['content'][0]['data']));
        $msg['delivered'] = 1;
        $msg['seen'] = 0;
        $msg['replied'] = 0;
        $msg['uri'] = notags(unxmlify($base['id'][0]['data']));
        $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data']));
        $msg['created'] = datetime_convert(notags(unxmlify('UTC', 'UTC', $base['sentdate'][0]['data'])));
        dbesc_array($msg);
        $r = q("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) . "`) VALUES ('" . implode("', '", array_values($msg)) . "')");
        require_once 'bbcode.php';
        if ($importer['notify-flags'] & NOTIFY_MAIL) {
            $tpl = file_get_contents('view/mail_received_eml.tpl');
            $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $msg['from-name'], '$title' => $msg['title'], '$body' => strip_tags(bbcode($msg['body']))));
            $res = mail($importer['email'], t("New mail received at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname());
        }
        xml_status(0);
        return;
        // NOTREACHED
    }
    if ($importer['readonly'] && !x($a->config['rockstar'])) {
        // This contact is readonly and we're going to ignore him/her, except if we're in
        // RockStar configuration. Us rockstars wan't people to talk about us. We just don't
        // want to have to deal with them individually. So our "readonly" fans can post to
        // our wall and comment, but they can't send us email.
        xml_status(0);
        return;
        // NOTREACHED
    }
    foreach ($feed->get_items() as $item) {
        $deleted = false;
        $rawdelete = $item->get_item_tags("http://purl.org/atompub/tombstones/1.0", 'deleted-entry');
        if (isset($rawdelete[0]['attribs']['']['ref'])) {
            $uri = $rawthread[0]['attribs']['']['ref'];
            $deleted = true;
            if (isset($rawdelete[0]['attribs']['']['when'])) {
                $when = $rawthread[0]['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) {
            $r = q("SELECT * FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($uri));
            if (count($r)) {
                $item = $r[0];
                if ($item['uri'] == $item['parent-uri']) {
                    $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s' , `changed` = '%s'\n\t\t\t\t\t\tWHERE `parent-uri` = '%s'", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']));
                } else {
                    $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s' , `changed` = '%s' \n\t\t\t\t\t\tWHERE `uri` = '%s' LIMIT 1", dbesc($when), dbesc(datetime_convert()), dbesc($uri));
                }
                if ($item['last-child']) {
                    // ensure that last-child is set in case the comment that had it just got wiped.
                    $q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' ", dbesc(datetime_convert()), dbesc($item['parent-uri']));
                    // who is the last child now?
                    $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 \n\t\t\t\t\t\tORDER BY `edited` DESC LIMIT 1", dbesc($item['parent-uri']));
                    if (count($r)) {
                        q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1", intval($r[0]['id']));
                    }
                }
            }
            continue;
        }
        $is_reply = false;
        $item_id = $item->get_id();
        $rawthread = $item->get_item_tags("http://purl.org/syndication/thread/1.0", 'in-reply-to');
        if (isset($rawthread[0]['attribs']['']['ref'])) {
            $is_reply = true;
            $parent_uri = $rawthread[0]['attribs']['']['ref'];
        }
        if ($is_reply) {
            if ($feed->get_item_quantity() == 1) {
                // remote reply to our post. Import and then notify everybody else.
                $datarray = get_atom_elements($item);
                $datarray['wall'] = 1;
                $datarray['type'] = 'remote-comment';
                $datarray['parent-uri'] = $parent_uri;
                $datarray['contact-id'] = $importer['id'];
                $posted_id = post_remote($a, $datarray);
                if ($posted_id) {
                    $r = q("SELECT `parent` FROM `item` WHERE `id` = %d LIMIT 1", intval($posted_id));
                    if (count($r)) {
                        $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d", dbesc(datetime_convert()), intval($r[0]['parent']));
                    }
                    $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($posted_id));
                    $php_path = strlen($a->config['php_path']) ? $a->config['php_path'] : 'php';
                    proc_close(proc_open("\"{$php_path}\" \"include/notifier.php\" \"comment-import\" \"{$posted_id}\" &", array(), $foo));
                    if ($importer['notify-flags'] & NOTIFY_COMMENT && !$importer['self']) {
                        require_once 'bbcode.php';
                        $from = stripslashes($datarray['author-name']);
                        $tpl = file_get_contents('view/cmnt_received_eml.tpl');
                        $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $from, '$body' => strip_tags(bbcode(stripslashes($datarray['body'])))));
                        $res = mail($importer['email'], $from . t(" commented on your item at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname());
                    }
                }
                xml_status(0);
                return;
            } else {
                // regular comment that is part of this total conversation. Have we seen it? If not, import it.
                $item_id = $item->get_id();
                $r = q("SELECT `last-child`, `edited` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($item_id));
                // FIXME update content if 'updated' changes
                if (count($r)) {
                    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                    if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                        $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id));
                    }
                    continue;
                }
                $datarray = get_atom_elements($item);
                $datarray['parent-uri'] = $parent_uri;
                $datarray['contact-id'] = $importer['id'];
                $r = post_remote($a, $datarray);
                // find out if our user is involved in this conversation and wants to be notified.
                if ($importer['notify-flags'] & NOTIFY_COMMENT) {
                    $myconv = q("SELECT `author-link` FROM `item` WHERE `parent-uri` = '%s'", dbesc($parent_uri));
                    if (count($myconv)) {
                        foreach ($myconv as $conv) {
                            if ($conv['author-link'] != $importer['url']) {
                                continue;
                            }
                            require_once 'bbcode.php';
                            $from = stripslashes($datarray['author-name']);
                            $tpl = file_get_contents('view/cmnt_received_eml.tpl');
                            $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $from, '$body' => strip_tags(bbcode(stripslashes($datarray['body'])))));
                            $res = mail($importer['email'], $from . t(" commented on an item at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname());
                            break;
                        }
                    }
                }
                continue;
            }
        } else {
            // Head post of a conversation. Have we seen it? If not, import it.
            $item_id = $item->get_id();
            $r = q("SELECT `last-child`, `edited` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($item_id));
            if (count($r)) {
                $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                    $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id));
                }
                continue;
            }
            $datarray = get_atom_elements($item);
            $datarray['parent-uri'] = $item_id;
            $datarray['contact-id'] = $importer['id'];
            $r = post_remote($a, $datarray);
            continue;
        }
    }
    xml_status(0);
    killme();
}
コード例 #6
0
ファイル: dfrn_confirm.php プロジェクト: vinzv/friendica
function dfrn_confirm_post(&$a, $handsfree = null)
{
    if (is_array($handsfree)) {
        /**
         * We were called directly from dfrn_request due to automatic friend acceptance.
         * Any $_POST parameters we may require are supplied in the $handsfree array.
         *
         */
        $node = $handsfree['node'];
        $a->interactive = false;
        // notice() becomes a no-op since nobody is there to see it
    } else {
        if ($a->argc > 1) {
            $node = $a->argv[1];
        }
    }
    /**
     *
     * Main entry point. Scenario 1. Our user received a friend request notification (perhaps
     * from another site) and clicked 'Approve'.
     * $POST['source_url'] is not set. If it is, it indicates Scenario 2.
     *
     * We may also have been called directly from dfrn_request ($handsfree != null) due to
     * this being a page type which supports automatic friend acceptance. That is also Scenario 1
     * since we are operating on behalf of our registered user to approve a friendship.
     *
     */
    if (!x($_POST, 'source_url')) {
        $uid = is_array($handsfree) ? $handsfree['uid'] : local_user();
        if (!$uid) {
            notice(t('Permission denied.') . EOL);
            return;
        }
        $user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
        if (!$user) {
            notice(t('Profile not found.') . EOL);
            return;
        }
        // These data elements may come from either the friend request notification form or $handsfree array.
        if (is_array($handsfree)) {
            logger('Confirm in handsfree mode');
            $dfrn_id = $handsfree['dfrn_id'];
            $intro_id = $handsfree['intro_id'];
            $duplex = $handsfree['duplex'];
            $hidden = array_key_exists('hidden', $handsfree) ? intval($handsfree['hidden']) : 0;
            $activity = array_key_exists('activity', $handsfree) ? intval($handsfree['activity']) : 0;
        } else {
            $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : "";
            $intro_id = x($_POST, 'intro_id') ? intval($_POST['intro_id']) : 0;
            $duplex = x($_POST, 'duplex') ? intval($_POST['duplex']) : 0;
            $cid = x($_POST, 'contact_id') ? intval($_POST['contact_id']) : 0;
            $hidden = x($_POST, 'hidden') ? intval($_POST['hidden']) : 0;
            $activity = x($_POST, 'activity') ? intval($_POST['activity']) : 0;
        }
        /**
         *
         * Ensure that dfrn_id has precedence when we go to find the contact record.
         * We only want to search based on contact id if there is no dfrn_id,
         * e.g. for OStatus network followers.
         *
         */
        if (strlen($dfrn_id)) {
            $cid = 0;
        }
        logger('Confirming request for dfrn_id (issued) ' . $dfrn_id);
        if ($cid) {
            logger('Confirming follower with contact_id: ' . $cid);
        }
        /**
         *
         * The other person will have been issued an ID when they first requested friendship.
         * Locate their record. At this time, their record will have both pending and blocked set to 1.
         * There won't be any dfrn_id if this is a network follower, so use the contact_id instead.
         *
         */
        $r = q("SELECT * FROM `contact` WHERE ( ( `issued-id` != '' AND `issued-id` = '%s' ) OR ( `id` = %d AND `id` != 0 ) ) AND `uid` = %d AND `duplex` = 0 LIMIT 1", dbesc($dfrn_id), intval($cid), intval($uid));
        if (!count($r)) {
            logger('Contact not found in DB.');
            notice(t('Contact not found.') . EOL);
            notice(t('This may occasionally happen if contact was requested by both persons and it has already been approved.') . EOL);
            return;
        }
        $contact = $r[0];
        $contact_id = $contact['id'];
        $relation = $contact['rel'];
        $site_pubkey = $contact['site-pubkey'];
        $dfrn_confirm = $contact['confirm'];
        $aes_allow = $contact['aes_allow'];
        $network = strlen($contact['issued-id']) ? NETWORK_DFRN : NETWORK_OSTATUS;
        if ($contact['network']) {
            $network = $contact['network'];
        }
        if ($network === NETWORK_DFRN) {
            /**
             *
             * Generate a key pair for all further communications with this person.
             * We have a keypair for every contact, and a site key for unknown people.
             * This provides a means to carry on relationships with other people if
             * any single key is compromised. It is a robust key. We're much more
             * worried about key leakage than anybody cracking it.
             *
             */
            require_once 'include/crypto.php';
            $res = new_keypair(4096);
            $private_key = $res['prvkey'];
            $public_key = $res['pubkey'];
            // Save the private key. Send them the public key.
            $r = q("UPDATE `contact` SET `prvkey` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($private_key), intval($contact_id), intval($uid));
            $params = array();
            /**
             *
             * Per the DFRN protocol, we will verify both ends by encrypting the dfrn_id with our
             * site private key (person on the other end can decrypt it with our site public key).
             * Then encrypt our profile URL with the other person's site public key. They can decrypt
             * it with their site private key. If the decryption on the other end fails for either
             * item, it indicates tampering or key failure on at least one site and we will not be
             * able to provide a secure communication pathway.
             *
             * If other site is willing to accept full encryption, (aes_allow is 1 AND we have php5.3
             * or later) then we encrypt the personal public key we send them using AES-256-CBC and a
             * random key which is encrypted with their site public key.
             *
             */
            $src_aes_key = random_string();
            $result = '';
            openssl_private_encrypt($dfrn_id, $result, $user[0]['prvkey']);
            $params['dfrn_id'] = bin2hex($result);
            $params['public_key'] = $public_key;
            $my_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
            openssl_public_encrypt($my_url, $params['source_url'], $site_pubkey);
            $params['source_url'] = bin2hex($params['source_url']);
            if ($aes_allow && function_exists('openssl_encrypt')) {
                openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
                $params['aes_key'] = bin2hex($params['aes_key']);
                $params['public_key'] = bin2hex(openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key));
            }
            $params['dfrn_version'] = DFRN_PROTOCOL_VERSION;
            if ($duplex == 1) {
                $params['duplex'] = 1;
            }
            if ($user[0]['page-flags'] == PAGE_COMMUNITY) {
                $params['page'] = 1;
            }
            if ($user[0]['page-flags'] == PAGE_PRVGROUP) {
                $params['page'] = 2;
            }
            logger('Confirm: posting data to ' . $dfrn_confirm . ': ' . print_r($params, true), LOGGER_DATA);
            /**
             *
             * POST all this stuff to the other site.
             * Temporarily raise the network timeout to 120 seconds because the default 60
             * doesn't always give the other side quite enough time to decrypt everything.
             *
             */
            $a->config['system']['curl_timeout'] = 120;
            $res = post_url($dfrn_confirm, $params);
            logger(' Confirm: received data: ' . $res, LOGGER_DATA);
            // Now figure out what they responded. Try to be robust if the remote site is
            // having difficulty and throwing up errors of some kind.
            $leading_junk = substr($res, 0, strpos($res, '<?xml'));
            $res = substr($res, strpos($res, '<?xml'));
            if (!strlen($res)) {
                // No XML at all, this exchange is messed up really bad.
                // We shouldn't proceed, because the xml parser might choke,
                // and $status is going to be zero, which indicates success.
                // We can hardly call this a success.
                notice(t('Response from remote site was not understood.') . EOL);
                return;
            }
            if (strlen($leading_junk) && get_config('system', 'debugging')) {
                // This might be more common. Mixed error text and some XML.
                // If we're configured for debugging, show the text. Proceed in either case.
                notice(t('Unexpected response from remote site: ') . EOL . $leading_junk . EOL);
            }
            if (stristr($res, "<status") === false) {
                // wrong xml! stop here!
                notice(t('Unexpected response from remote site: ') . EOL . htmlspecialchars($res) . EOL);
                return;
            }
            $xml = parse_xml_string($res);
            $status = (int) $xml->status;
            $message = unxmlify($xml->message);
            // human readable text of what may have gone wrong.
            switch ($status) {
                case 0:
                    info(t("Confirmation completed successfully.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
                case 1:
                    // birthday paradox - generate new dfrn-id and fall through.
                    $new_dfrn_id = random_string();
                    $r = q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($new_dfrn_id), intval($contact_id), intval($uid));
                case 2:
                    notice(t("Temporary failure. Please wait and try again.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
                case 3:
                    notice(t("Introduction failed or was revoked.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
            }
            if ($status == 0 && $intro_id) {
                // Success. Delete the notification.
                $r = q("DELETE FROM `intro` WHERE `id` = %d AND `uid` = %d", intval($intro_id), intval($uid));
            }
            if ($status != 0) {
                return;
            }
        }
        /*
         *
         * We have now established a relationship with the other site.
         * Let's make our own personal copy of their profile photo so we don't have
         * to always load it from their site.
         *
         * We will also update the contact record with the nature and scope of the relationship.
         *
         */
        require_once 'include/Photo.php';
        $photos = import_profile_photo($contact['photo'], $uid, $contact_id);
        logger('dfrn_confirm: confirm - imported photos');
        if ($network === NETWORK_DFRN) {
            $new_relation = CONTACT_IS_FOLLOWER;
            if ($relation == CONTACT_IS_SHARING || $duplex) {
                $new_relation = CONTACT_IS_FRIEND;
            }
            if ($relation == CONTACT_IS_SHARING && $duplex) {
                $duplex = 0;
            }
            $r = q("UPDATE `contact` SET\n\t\t\t\t`photo` = '%s',\n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`micro` = '%s',\n\t\t\t\t`rel` = %d,\n\t\t\t\t`name-date` = '%s',\n\t\t\t\t`uri-date` = '%s',\n\t\t\t\t`avatar-date` = '%s',\n\t\t\t\t`blocked` = 0,\n\t\t\t\t`pending` = 0,\n\t\t\t\t`duplex` = %d,\n\t\t\t\t`hidden` = %d,\n\t\t\t\t`network` = '%s' WHERE `id` = %d\n\t\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($new_relation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($hidden), dbesc(NETWORK_DFRN), intval($contact_id));
        } else {
            // $network !== NETWORK_DFRN
            $network = $contact['network'] ? $contact['network'] : NETWORK_OSTATUS;
            $notify = $contact['notify'] ? $contact['notify'] : '';
            $poll = $contact['poll'] ? $contact['poll'] : '';
            if (!$contact['notify'] || !$contact['poll']) {
                $arr = lrdd($contact['url']);
                if (count($arr)) {
                    foreach ($arr as $link) {
                        if ($link['@attributes']['rel'] === 'salmon') {
                            $notify = $link['@attributes']['href'];
                        }
                        if ($link['@attributes']['rel'] === NAMESPACE_FEED) {
                            $poll = $link['@attributes']['href'];
                        }
                    }
                }
            }
            $new_relation = $contact['rel'];
            $writable = $contact['writable'];
            if ($network === NETWORK_DIASPORA) {
                if ($duplex) {
                    $new_relation = CONTACT_IS_FRIEND;
                } else {
                    $new_relation = CONTACT_IS_FOLLOWER;
                }
                if ($new_relation != CONTACT_IS_FOLLOWER) {
                    $writable = 1;
                }
            }
            $r = q("DELETE FROM `intro` WHERE `id` = %d AND `uid` = %d", intval($intro_id), intval($uid));
            $r = q("UPDATE `contact` SET `photo` = '%s',\n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`micro` = '%s',\n\t\t\t\t`name-date` = '%s',\n\t\t\t\t`uri-date` = '%s',\n\t\t\t\t`avatar-date` = '%s',\n\t\t\t\t`notify` = '%s',\n\t\t\t\t`poll` = '%s',\n\t\t\t\t`blocked` = 0,\n\t\t\t\t`pending` = 0,\n\t\t\t\t`network` = '%s',\n\t\t\t\t`writable` = %d,\n\t\t\t\t`hidden` = %d,\n\t\t\t\t`rel` = %d\n\t\t\t\tWHERE `id` = %d\n\t\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($notify), dbesc($poll), dbesc($network), intval($writable), intval($hidden), intval($new_relation), intval($contact_id));
        }
        if ($r === false) {
            notice(t('Unable to set contact photo.') . EOL);
        }
        // reload contact info
        $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (count($r)) {
            $contact = $r[0];
        } else {
            $contact = null;
        }
        if (isset($new_relation) && $new_relation == CONTACT_IS_FRIEND) {
            if ($contact && $contact['network'] === NETWORK_DIASPORA) {
                require_once 'include/diaspora.php';
                $ret = diaspora_share($user[0], $r[0]);
                logger('mod_follow: diaspora_share returns: ' . $ret);
            }
            // Send a new friend post if we are allowed to...
            $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", intval($uid));
            if (count($r) && $r[0]['hide-friends'] == 0 && $activity && !$hidden) {
                require_once 'include/items.php';
                $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($uid));
                if (count($self)) {
                    $arr = array();
                    $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $uid);
                    $arr['uid'] = $uid;
                    $arr['contact-id'] = $self[0]['id'];
                    $arr['wall'] = 1;
                    $arr['type'] = 'wall';
                    $arr['gravity'] = 0;
                    $arr['origin'] = 1;
                    $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
                    $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
                    $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
                    $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
                    $APhoto = '[url=' . $self[0]['url'] . ']' . '[img]' . $self[0]['thumb'] . '[/img][/url]';
                    $B = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
                    $BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
                    $arr['verb'] = ACTIVITY_FRIEND;
                    $arr['object-type'] = ACTIVITY_OBJ_PERSON;
                    $arr['body'] = sprintf(t('%1$s is now friends with %2$s'), $A, $B) . "\n\n\n" . $BPhoto;
                    $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $contact['name'] . '</title>' . '<id>' . $contact['url'] . '/' . $contact['name'] . '</id>';
                    $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $contact['url'] . '" />' . "\n");
                    $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $contact['thumb'] . '" />' . "\n");
                    $arr['object'] .= '</link></object>' . "\n";
                    $arr['last-child'] = 1;
                    $arr['allow_cid'] = $user[0]['allow_cid'];
                    $arr['allow_gid'] = $user[0]['allow_gid'];
                    $arr['deny_cid'] = $user[0]['deny_cid'];
                    $arr['deny_gid'] = $user[0]['deny_gid'];
                    $i = item_store($arr);
                    if ($i) {
                        proc_run('php', "include/notifier.php", "activity", "{$i}");
                    }
                }
            }
        }
        $g = q("select def_gid from user where uid = %d limit 1", intval($uid));
        if ($contact && $g && intval($g[0]['def_gid'])) {
            require_once 'include/group.php';
            group_add_member($uid, '', $contact['id'], $g[0]['def_gid']);
        }
        // Let's send our user to the contact editor in case they want to
        // do anything special with this new friend.
        if ($handsfree === null) {
            goaway($a->get_baseurl() . '/contacts/' . intval($contact_id));
        } else {
            return;
        }
        //NOTREACHED
    }
    /**
     *
     *
     * End of Scenario 1. [Local confirmation of remote friend request].
     *
     * Begin Scenario 2. This is the remote response to the above scenario.
     * This will take place on the site that originally initiated the friend request.
     * In the section above where the confirming party makes a POST and
     * retrieves xml status information, they are communicating with the following code.
     *
     */
    if (x($_POST, 'source_url')) {
        // We are processing an external confirmation to an introduction created by our user.
        $public_key = x($_POST, 'public_key') ? $_POST['public_key'] : '';
        $dfrn_id = x($_POST, 'dfrn_id') ? hex2bin($_POST['dfrn_id']) : '';
        $source_url = x($_POST, 'source_url') ? hex2bin($_POST['source_url']) : '';
        $aes_key = x($_POST, 'aes_key') ? $_POST['aes_key'] : '';
        $duplex = x($_POST, 'duplex') ? intval($_POST['duplex']) : 0;
        $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
        $version_id = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
        $forum = $page == 1 ? 1 : 0;
        $prv = $page == 2 ? 1 : 0;
        logger('dfrn_confirm: requestee contacted: ' . $node);
        logger('dfrn_confirm: request: POST=' . print_r($_POST, true), LOGGER_DATA);
        // If $aes_key is set, both of these items require unpacking from the hex transport encoding.
        if (x($aes_key)) {
            $aes_key = hex2bin($aes_key);
            $public_key = hex2bin($public_key);
        }
        // Find our user's account
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", dbesc($node));
        if (!count($r)) {
            $message = sprintf(t('No user record found for \'%s\' '), $node);
            xml_status(3, $message);
            // failure
            // NOTREACHED
        }
        $my_prvkey = $r[0]['prvkey'];
        $local_uid = $r[0]['uid'];
        if (!strstr($my_prvkey, 'PRIVATE KEY')) {
            $message = t('Our site encryption key is apparently messed up.');
            xml_status(3, $message);
        }
        // verify everything
        $decrypted_source_url = "";
        openssl_private_decrypt($source_url, $decrypted_source_url, $my_prvkey);
        if (!strlen($decrypted_source_url)) {
            $message = t('Empty site URL was provided or URL could not be decrypted by us.');
            xml_status(3, $message);
            // NOTREACHED
        }
        $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($decrypted_source_url), intval($local_uid));
        if (!count($ret)) {
            if (strstr($decrypted_source_url, 'http:')) {
                $newurl = str_replace('http:', 'https:', $decrypted_source_url);
            } else {
                $newurl = str_replace('https:', 'http:', $decrypted_source_url);
            }
            $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($newurl), intval($local_uid));
            if (!count($ret)) {
                // this is either a bogus confirmation (?) or we deleted the original introduction.
                $message = t('Contact record was not found for you on our site.');
                xml_status(3, $message);
                return;
                // NOTREACHED
            }
        }
        $relation = $ret[0]['rel'];
        // Decrypt all this stuff we just received
        $foreign_pubkey = $ret[0]['site-pubkey'];
        $dfrn_record = $ret[0]['id'];
        if (!$foreign_pubkey) {
            $message = sprintf(t('Site public key not available in contact record for URL %s.'), $newurl);
            xml_status(3, $message);
        }
        $decrypted_dfrn_id = "";
        openssl_public_decrypt($dfrn_id, $decrypted_dfrn_id, $foreign_pubkey);
        if (strlen($aes_key)) {
            $decrypted_aes_key = "";
            openssl_private_decrypt($aes_key, $decrypted_aes_key, $my_prvkey);
            $dfrn_pubkey = openssl_decrypt($public_key, 'AES-256-CBC', $decrypted_aes_key);
        } else {
            $dfrn_pubkey = $public_key;
        }
        $r = q("SELECT * FROM `contact` WHERE `dfrn-id` = '%s' LIMIT 1", dbesc($decrypted_dfrn_id));
        if (count($r)) {
            $message = t('The ID provided by your system is a duplicate on our system. It should work if you try again.');
            xml_status(1, $message);
            // Birthday paradox - duplicate dfrn-id
            // NOTREACHED
        }
        $r = q("UPDATE `contact` SET `dfrn-id` = '%s', `pubkey` = '%s' WHERE `id` = %d", dbesc($decrypted_dfrn_id), dbesc($dfrn_pubkey), intval($dfrn_record));
        if (!count($r)) {
            $message = t('Unable to set your contact credentials on our system.');
            xml_status(3, $message);
        }
        // It's possible that the other person also requested friendship.
        // If it is a duplex relationship, ditch the issued-id if one exists.
        if ($duplex) {
            $r = q("UPDATE `contact` SET `issued-id` = '' WHERE `id` = %d", intval($dfrn_record));
        }
        // We're good but now we have to scrape the profile photo and send notifications.
        $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($dfrn_record));
        if (count($r)) {
            $photo = $r[0]['photo'];
        } else {
            $photo = $a->get_baseurl() . '/images/person-175.jpg';
        }
        require_once "include/Photo.php";
        $photos = import_profile_photo($photo, $local_uid, $dfrn_record);
        logger('dfrn_confirm: request - photos imported');
        $new_relation = CONTACT_IS_SHARING;
        if ($relation == CONTACT_IS_FOLLOWER || $duplex) {
            $new_relation = CONTACT_IS_FRIEND;
        }
        if ($relation == CONTACT_IS_FOLLOWER && $duplex) {
            $duplex = 0;
        }
        $r = q("UPDATE `contact` SET\n\t\t\t`photo` = '%s',\n\t\t\t`thumb` = '%s',\n\t\t\t`micro` = '%s',\n\t\t\t`rel` = %d,\n\t\t\t`name-date` = '%s',\n\t\t\t`uri-date` = '%s',\n\t\t\t`avatar-date` = '%s',\n\t\t\t`blocked` = 0,\n\t\t\t`pending` = 0,\n\t\t\t`duplex` = %d,\n\t\t\t`forum` = %d,\n\t\t\t`prv` = %d,\n\t\t\t`network` = '%s' WHERE `id` = %d\n\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($new_relation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($forum), intval($prv), dbesc(NETWORK_DFRN), intval($dfrn_record));
        if ($r === false) {
            // indicates schema is messed up or total db failure
            $message = t('Unable to update your contact profile details on our system');
            xml_status(3, $message);
        }
        // Otherwise everything seems to have worked and we are almost done. Yay!
        // Send an email notification
        logger('dfrn_confirm: request: info updated');
        $r = q("SELECT `contact`.*, `user`.* FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\tWHERE `contact`.`id` = %d LIMIT 1", intval($dfrn_record));
        if (count($r)) {
            $combined = $r[0];
        }
        if (count($r) && $r[0]['notify-flags'] & NOTIFY_CONFIRM) {
            $mutual = $new_relation == CONTACT_IS_FRIEND;
            notification(array('type' => NOTIFY_CONFIRM, 'notify_flags' => $r[0]['notify-flags'], 'language' => $r[0]['language'], 'to_name' => $r[0]['username'], 'to_email' => $r[0]['email'], 'uid' => $r[0]['uid'], 'link' => $a->get_baseurl() . '/contacts/' . $dfrn_record, 'source_name' => strlen(stripslashes($r[0]['name'])) ? stripslashes($r[0]['name']) : t('[Name Withheld]'), 'source_link' => $r[0]['url'], 'source_photo' => $r[0]['photo'], 'verb' => $mutual ? ACTIVITY_FRIEND : ACTIVITY_FOLLOW, 'otype' => 'intro'));
        }
        // Send a new friend post if we are allowed to...
        if ($page && intval(get_pconfig($local_uid, 'system', 'post_joingroup'))) {
            $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", intval($local_uid));
            if (count($r) && $r[0]['hide-friends'] == 0) {
                require_once 'include/items.php';
                $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($local_uid));
                if (count($self)) {
                    $arr = array();
                    $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $local_uid);
                    $arr['uid'] = $local_uid;
                    $arr['contact-id'] = $self[0]['id'];
                    $arr['wall'] = 1;
                    $arr['type'] = 'wall';
                    $arr['gravity'] = 0;
                    $arr['origin'] = 1;
                    $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
                    $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
                    $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
                    $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
                    $APhoto = '[url=' . $self[0]['url'] . ']' . '[img]' . $self[0]['thumb'] . '[/img][/url]';
                    $B = '[url=' . $combined['url'] . ']' . $combined['name'] . '[/url]';
                    $BPhoto = '[url=' . $combined['url'] . ']' . '[img]' . $combined['thumb'] . '[/img][/url]';
                    $arr['verb'] = ACTIVITY_JOIN;
                    $arr['object-type'] = ACTIVITY_OBJ_GROUP;
                    $arr['body'] = sprintf(t('%1$s has joined %2$s'), $A, $B) . "\n\n\n" . $BPhoto;
                    $arr['object'] = '<object><type>' . ACTIVITY_OBJ_GROUP . '</type><title>' . $combined['name'] . '</title>' . '<id>' . $combined['url'] . '/' . $combined['name'] . '</id>';
                    $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $combined['url'] . '" />' . "\n");
                    $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $combined['thumb'] . '" />' . "\n");
                    $arr['object'] .= '</link></object>' . "\n";
                    $arr['last-child'] = 1;
                    $arr['allow_cid'] = $user[0]['allow_cid'];
                    $arr['allow_gid'] = $user[0]['allow_gid'];
                    $arr['deny_cid'] = $user[0]['deny_cid'];
                    $arr['deny_gid'] = $user[0]['deny_gid'];
                    $i = item_store($arr);
                    if ($i) {
                        proc_run('php', "include/notifier.php", "activity", "{$i}");
                    }
                }
            }
        }
        xml_status(0);
        // Success
        return;
        // NOTREACHED
        ////////////////////// End of this scenario ///////////////////////////////////////////////
    }
    // somebody arrived here by mistake or they are fishing. Send them to the homepage.
    goaway(z_root());
    // NOTREACHED
}
コード例 #7
0
function dfrn_confirm_post(&$a)
{
    if ($a->argc > 1) {
        $node = $a->argv[1];
    }
    if (x($_POST, 'source_url')) {
        // We are processing an external confirmation to an introduction created by our user.
        $public_key = $_POST['public_key'];
        $dfrn_id = $_POST['dfrn_id'];
        $source_url = $_POST['source_url'];
        $aes_key = $_POST['aes_key'];
        $duplex = $_POST['duplex'];
        $version_id = $_POST['dfrn_version'];
        // Find our user's account
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", dbesc($node));
        if (!count($r)) {
            xml_status(3);
            // failure
            return;
            // NOTREACHED
        }
        $my_prvkey = $r[0]['prvkey'];
        $local_uid = $r[0]['uid'];
        // verify everything
        $decrypted_source_url = "";
        openssl_private_decrypt($source_url, $decrypted_source_url, $my_prvkey);
        $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' LIMIT 1", dbesc($decrypted_source_url));
        if (!count($ret)) {
            // this is either a bogus confirmation or we deleted the original introduction.
            xml_status(3);
            return;
            // NOTREACHED
        }
        $relation = $ret[0]['rel'];
        // Decrypt all this stuff we just received
        $foreign_pubkey = $ret[0]['site-pubkey'];
        $dfrn_record = $ret[0]['id'];
        $decrypted_dfrn_id = "";
        openssl_public_decrypt($dfrn_id, $decrypted_dfrn_id, $foreign_pubkey);
        if (strlen($aes_key)) {
            $decrypted_aes_key = "";
            openssl_private_decrypt($aes_key, $decrypted_aes_key, $my_prvkey);
            $dfrn_pubkey = openssl_decrypt($public_key, 'AES-256-CBC', $decrypted_aes_key);
        } else {
            $dfrn_pubkey = $public_key;
        }
        $r = q("SELECT * FROM `contact` WHERE `dfrn-id` = '%s' LIMIT 1", dbesc($decrypted_dfrn_id), intval($local_uid));
        if (count($r)) {
            xml_status(1);
            // Birthday paradox - duplicate dfrn-id
            return;
            // NOTREACHED
        }
        $r = q("UPDATE `contact` SET `dfrn-id` = '%s', `pubkey` = '%s' WHERE `id` = %d LIMIT 1", dbesc($decrypted_dfrn_id), dbesc($dfrn_pubkey), intval($dfrn_record));
        if ($r) {
            // We're good but now we have to scrape the profile photo and send notifications.
            require_once "Photo.php";
            $photo_failure = false;
            $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($dfrn_record));
            if (count($r)) {
                $filename = basename($r[0]['photo']);
                $img_str = fetch_url($r[0]['photo'], true);
                $img = new Photo($img_str);
                if ($img) {
                    $img->scaleImageSquare(175);
                    $hash = hash('md5', uniqid(mt_rand(), true));
                    $r = $img->store($dfrn_record, $hash, $filename, t('Contact Photos'), 4);
                    if ($r === false) {
                        $photo_failure = true;
                    }
                    $img->scaleImage(80);
                    $r = $img->store($dfrn_record, $hash, $filename, t('Contact Photos'), 5);
                    if ($r === false) {
                        $photo_failure = true;
                    }
                    $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
                    $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
                } else {
                    $photo_failure = true;
                }
            } else {
                $photo_failure = true;
            }
            if ($photo_failure) {
                $photo = $a->get_baseurl() . '/images/default-profile.jpg';
                $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
            }
            $new_relation = DIRECTION_OUT;
            if ($relation == DIRECTION_IN || $duplex) {
                $new_relation = DIRECTION_BOTH;
            }
            $r = q("UPDATE `contact` SET \n\t\t\t\t`photo` = '%s',\n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`rel` = %d,\n\t\t\t\t`name-date` = '%s',\n\t\t\t\t`uri-date` = '%s',\n\t\t\t\t`avatar-date` = '%s',\n\t\t\t\t`blocked` = 0,\n\t\t\t\t`pending` = 0,\n\t\t\t\t`duplex` = %d\n\t\t\t\t`network` = 'dfrn' WHERE `id` = %d LIMIT 1\n\t\t\t", dbesc($photo), dbesc($thumb), intval($newrelation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($dfrn_record));
            if ($r === false) {
                notice(t("Unable to set contact photo info.") . EOL);
            }
            // Otherwise everything seems to have worked and we are almost done. Yay!
            // Send an email notification
            $r = q("SELECT * FROM `contact` LEFT JOIN `user` ON `user`.`uid` = 1\n\t\t\t\tWHERE `contact`.`id` = %d LIMIT 1", intval($dfrn_record));
            if (count($r) && $r[0]['notify-flags'] & NOTIFY_CONFIRM) {
                $tpl = file_get_contents('view/intro_complete_eml.tpl');
                $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $r[0]['username'], '$email' => $r[0]['email'], '$fn' => $r[0]['name'], '$dfrn_url' => $r[0]['url']));
                $res = mail($r[0]['email'], t("Introduction accepted at ") . $a->config['sitename'], $email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER[SERVER_NAME]);
                if (!$res) {
                    notice(t("Email notification failed.") . EOL);
                }
            }
            xml_status(0);
            // Success
            return;
            // NOTREACHED
        } else {
            xml_status(2);
            // Hopefully temporary problem that can be retried.
        }
        return;
        // NOTREACHED
        ////////////////////// End of this scenario ///////////////////////////////////////////////
    } else {
        // We are processing a local confirmation initiated on this system by our user to an external introduction.
        $uid = get_uid();
        if (!$uid) {
            notice(t("Permission denied.") . EOL);
            return;
        }
        $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : "";
        $intro_id = intval($_POST['intro_id']);
        $duplex = intval($_POST['duplex']);
        $r = q("SELECT * FROM `contact` WHERE `issued-id` = '%s' LIMIT 1", dbesc($dfrn_id));
        if (!count($r)) {
            notice(t('Node does not exist.') . EOL);
            return;
        }
        $contact_id = $r[0]['id'];
        $relation = $r[0]['rel'];
        $site_pubkey = $r[0]['site-pubkey'];
        $dfrn_confirm = $r[0]['confirm'];
        $aes_allow = $r[0]['aes_allow'];
        $res = openssl_pkey_new(array('digest_alg' => 'whirlpool', 'private_key_bits' => 4096, 'encrypt_key' => false));
        $private_key = '';
        openssl_pkey_export($res, $private_key);
        $pubkey = openssl_pkey_get_details($res);
        $public_key = $pubkey["key"];
        $r = q("UPDATE `contact` SET `issued-pubkey` = '%s', `prvkey` = '%s' WHERE `id` = %d LIMIT 1", dbesc($public_key), dbesc($private_key), intval($contact_id));
        $params = array();
        $src_aes_key = random_string();
        $result = '';
        openssl_private_encrypt($dfrn_id, $result, $a->user['prvkey']);
        $params['dfrn_id'] = $result;
        $params['public_key'] = $public_key;
        openssl_public_encrypt($_SESSION['my_url'], $params['source_url'], $site_pubkey);
        if ($aes_allow && function_exists('openssl_encrypt')) {
            openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
            $params['public_key'] = openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key);
        }
        $params['dfrn_version'] = '2.0';
        if ($duplex == 1) {
            $params['duplex'] = 1;
        }
        $res = post_url($dfrn_confirm, $params);
        // uncomment the following two lines and comment the following xml/status lines
        // to debug the remote confirmation section (when both confirmations
        // and responses originate on this system)
        // echo $res;
        // $status = 0;
        $xml = simplexml_load_string($res);
        $status = (int) $xml->status;
        switch ($status) {
            case 0:
                notice(t("Confirmation completed successfully") . EOL);
                break;
            case 1:
                // birthday paradox - generate new dfrn-id and fall through.
                $new_dfrn_id = random_string();
                $r = q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d LIMIT 1", dbesc($new_dfrn_id), intval($contact_id));
            case 2:
                notice(t("Temporary failure. Please wait and try again.") . EOL);
                break;
            case 3:
                notice(t("Introduction failed or was revoked. Cannot complete.") . EOL);
                break;
        }
        if (($status == 0 || $status == 3) && $intro_id) {
            //delete the notification
            $r = q("DELETE FROM `intro` WHERE `id` = %d LIMIT 1", intval($intro_id));
        }
        if ($status != 0) {
            return;
        }
        require_once "Photo.php";
        $photo_failure = false;
        $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (count($r)) {
            $filename = basename($r[0]['photo']);
            $img_str = fetch_url($r[0]['photo'], true);
            $img = new Photo($img_str);
            if ($img) {
                $img->scaleImageSquare(175);
                $hash = hash('md5', uniqid(mt_rand(), true));
                $r = $img->store($contact_id, $hash, $filename, t('Contact Photos'), 4);
                if ($r === false) {
                    $photo_failure = true;
                }
                $img->scaleImage(80);
                $r = $img->store($contact_id, $hash, $filename, t('Contact Photos'), 5);
                if ($r === false) {
                    $photo_failure = true;
                }
                $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
                $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
            } else {
                $photo_failure = true;
            }
        } else {
            $photo_failure = true;
        }
        if ($photo_failure) {
            $photo = $a->get_baseurl() . '/images/default-profile.jpg';
            $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
        }
        $new_relation = DIRECTION_IN;
        if ($relation == DIRECTION_OUT || $duplex) {
            $new_relation = DIRECTION_BOTH;
        }
        $r = q("UPDATE `contact` SET \n\t\t\t`photo` = '%s', \n\t\t\t`thumb` = '%s', \n\t\t\t`rel` = %d, \n\t\t\t`name-date` = '%s', \n\t\t\t`uri-date` = '%s', \n\t\t\t`avatar-date` = '%s', \n\t\t\t`blocked` = 0, \n\t\t\t`pending` = 0, \n\t\t\t`duplex` = %d,\n\t\t\t`network` = 'dfrn' WHERE `id` = %d LIMIT 1\n\t\t", dbesc($photo), dbesc($thumb), intval($newrelation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($contact_id));
        if ($r === false) {
            notice(t('Unable to set contact photo.') . EOL);
        }
        goaway($a->get_baseurl() . '/contacts/' . intval($contact_id));
        return;
        //NOTREACHED
    }
    return;
}
コード例 #8
0
ファイル: dfrn_notify.php プロジェクト: ZerGabriel/friendica
function dfrn_notify_post(&$a)
{
    logger(__FUNCTION__, LOGGER_TRACE);
    $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : '';
    $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
    $challenge = x($_POST, 'challenge') ? notags(trim($_POST['challenge'])) : '';
    $data = x($_POST, 'data') ? $_POST['data'] : '';
    $key = x($_POST, 'key') ? $_POST['key'] : '';
    $rino_remote = x($_POST, 'rino') ? intval($_POST['rino']) : 0;
    $dissolve = x($_POST, 'dissolve') ? intval($_POST['dissolve']) : 0;
    $perm = x($_POST, 'perm') ? notags(trim($_POST['perm'])) : 'r';
    $ssl_policy = x($_POST, 'ssl_policy') ? notags(trim($_POST['ssl_policy'])) : 'none';
    $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
    $forum = $page == 1 ? 1 : 0;
    $prv = $page == 2 ? 1 : 0;
    $writable = -1;
    if ($dfrn_version >= 2.21) {
        $writable = $perm === 'rw' ? 1 : 0;
    }
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
        xml_status(3);
    }
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s'", dbesc($dfrn_id), dbesc($challenge));
    // find the local user who owns this relationship.
    $sql_extra = '';
    switch ($direction) {
        case -1:
            $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
            break;
        case 0:
            $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        case 1:
            $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        default:
            xml_status(3);
            break;
            // NOTREACHED
    }
    // be careful - $importer will contain both the contact information for the contact
    // sending us the post, and also the user information for the person receiving it.
    // since they are mixed together, it is easy to get them confused.
    $r = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`,\n\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`,\n\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`,\n\t\t\t\t\t`contact`.`thumb` AS `thumb`,\n\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t`user`.*\n\t\t\tFROM `contact`\n\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\tAND `user`.`nickname` = '%s' AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 {$sql_extra} LIMIT 1", dbesc($a->argv[1]));
    if (!count($r)) {
        logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id);
        xml_status(3);
        //NOTREACHED
    }
    // $importer in this case contains the contact record for the remote contact joined with the user record of our user.
    $importer = $r[0];
    logger("Remote rino version: " . $rino_remote . " for " . $importer["url"], LOGGER_DEBUG);
    if ($writable != -1 && $writable != $importer['writable'] || $importer['forum'] != $forum || $importer['prv'] != $prv) {
        q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d", intval($writable == -1 ? $importer['writable'] : $writable), intval($forum), intval($prv), intval($importer['id']));
        if ($writable != -1) {
            $importer['writable'] = $writable;
        }
        $importer['forum'] = $page;
    }
    // if contact's ssl policy changed, update our links
    fix_contact_ssl_policy($importer, $ssl_policy);
    logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']);
    logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
    if ($dissolve == 1) {
        /**
         * Relationship is dissolved permanently
         */
        require_once 'include/Contact.php';
        contact_remove($importer['id']);
        logger('relationship dissolved : ' . $importer['name'] . ' dissolved ' . $importer['username']);
        xml_status(0);
    }
    // If we are setup as a soapbox we aren't accepting input from this person
    // This behaviour is deactivated since it really doesn't make sense to even disallow comments
    // The check if someone is a friend or simply a follower is done in a later place so it needn't to be done here
    //if($importer['page-flags'] == PAGE_SOAPBOX)
    //	xml_status(0);
    $rino = get_config('system', 'rino_encrypt');
    $rino = intval($rino);
    // use RINO1 if mcrypt isn't installed and RINO2 was selected
    if ($rino == 2 and !function_exists('mcrypt_create_iv')) {
        $rino = 1;
    }
    logger("Local rino version: " . $rino, LOGGER_DEBUG);
    if (strlen($key)) {
        // if local rino is lower than remote rino, abort: should not happen!
        // but only for $remote_rino > 1, because old code did't send rino version
        if ($rino_remote_version > 1 && $rino < $rino_remote) {
            logger("rino version '{$rino_remote}' is lower than supported '{$rino}'");
            xml_status(0, "rino version '{$rino_remote}' is lower than supported '{$rino}'");
        }
        $rawkey = hex2bin(trim($key));
        logger('rino: md5 raw key: ' . md5($rawkey));
        $final_key = '';
        if ($dfrn_version >= 2.1) {
            if ($importer['duplex'] && strlen($importer['cprvkey']) || !strlen($importer['cpubkey'])) {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            } else {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            }
        } else {
            if ($importer['duplex'] && strlen($importer['cpubkey']) || !strlen($importer['cprvkey'])) {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            } else {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            }
        }
        #logger('rino: received key : ' . $final_key);
        switch ($rino_remote) {
            case 0:
            case 1:
                // we got a key. old code send only the key, without RINO version.
                // we assume RINO 1 if key and no RINO version
                $data = aes_decrypt(hex2bin($data), $final_key);
                break;
            case 2:
                try {
                    $data = Crypto::decrypt(hex2bin($data), $final_key);
                } catch (InvalidCiphertext $ex) {
                    // VERY IMPORTANT
                    // Either:
                    //   1. The ciphertext was modified by the attacker,
                    //   2. The key is wrong, or
                    //   3. $ciphertext is not a valid ciphertext or was corrupted.
                    // Assume the worst.
                    logger('The ciphertext has been tampered with!');
                    xml_status(0, 'The ciphertext has been tampered with!');
                } catch (Ex\CryptoTestFailed $ex) {
                    logger('Cannot safely perform dencryption');
                    xml_status(0, 'CryptoTestFailed');
                } catch (Ex\CannotPerformOperation $ex) {
                    logger('Cannot safely perform decryption');
                    xml_status(0, 'Cannot safely perform decryption');
                }
                break;
            default:
                logger("rino: invalid sent verision '{$rino_remote}'");
                xml_status(0);
        }
        logger('rino: decrypted data: ' . $data, LOGGER_DATA);
    }
    $ret = local_delivery($importer, $data);
    xml_status($ret);
    // NOTREACHED
}