Example #1
0
 function dfrn_request_post(&$a)
 {
     if ($a->argc != 2 || !count($a->profile)) {
         return;
     }
     if ($_POST['cancel']) {
         goaway(z_root());
     }
     /**
      *
      * Scenario 2: We've introduced ourself to another cell, then have been returned to our own cell
      * to confirm the request, and then we've clicked submit (perhaps after logging in). 
      * That brings us here:
      *
      */
     if (x($_POST, 'localconfirm') && $_POST['localconfirm'] == 1) {
         /**
          * Ensure this is a valid request
          */
         if (local_user() && $a->user['nickname'] == $a->argv[1] && x($_POST, 'dfrn_url')) {
             $dfrn_url = notags(trim($_POST['dfrn_url']));
             $aes_allow = x($_POST, 'aes_allow') && $_POST['aes_allow'] == 1 ? 1 : 0;
             $confirm_key = x($_POST, 'confirm_key') ? $_POST['confirm_key'] : "";
             $contact_record = null;
             if (x($dfrn_url)) {
                 /**
                  * Lookup the contact based on their URL (which is the only unique thing we have at the moment)
                  */
                 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `self` = 0 LIMIT 1", intval(local_user()), dbesc($dfrn_url));
                 if (count($r)) {
                     if (strlen($r[0]['dfrn-id'])) {
                         /**
                          * We don't need to be here. It has already happened.
                          */
                         notice(t("This introduction has already been accepted.") . EOL);
                         return;
                     } else {
                         $contact_record = $r[0];
                     }
                 }
                 if (is_array($contact_record)) {
                     $r = q("UPDATE `contact` SET `ret-aes` = %d WHERE `id` = %d LIMIT 1", intval($aes_allow), intval($contact_record['id']));
                 } else {
                     /**
                      * Scrape the other site's profile page to pick up the dfrn links, key, fn, and photo
                      */
                     require_once 'Scrape.php';
                     $parms = scrape_dfrn($dfrn_url);
                     if (!count($parms)) {
                         notice(t('Profile location is not valid or does not contain profile information.') . EOL);
                         return;
                     } else {
                         if (!x($parms, 'fn')) {
                             notice(t('Warning: profile location has no identifiable owner name.') . EOL);
                         }
                         if (!x($parms, 'photo')) {
                             notice(t('Warning: profile location has no profile photo.') . EOL);
                         }
                         $invalid = validate_dfrn($parms);
                         if ($invalid) {
                             notice(sprintf(tt("%d required parameter was not found at the given location", "%d required parameters were not found at the given location", $invalid), $invalid) . EOL);
                             return;
                         }
                     }
                     $dfrn_request = $parms['dfrn-request'];
                     /********* Escape the entire array ********/
                     dbesc_array($parms);
                     /******************************************/
                     /**
                      * Create a contact record on our site for the other person
                      */
                     $r = q("INSERT INTO `contact` ( `uid`, `created`,`url`, `nurl`, `name`, `nick`, `photo`, `site-pubkey`,\n\t\t\t\t\t\t`request`, `confirm`, `notify`, `poll`, `poco`, `network`, `aes_allow`) \n\t\t\t\t\t\tVALUES ( %d, '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", intval(local_user()), datetime_convert(), dbesc($dfrn_url), dbesc(normalise_link($dfrn_url)), $parms['fn'], $parms['nick'], $parms['photo'], $parms['key'], $parms['dfrn-request'], $parms['dfrn-confirm'], $parms['dfrn-notify'], $parms['dfrn-poll'], $parms['dfrn-poco'], dbesc(NETWORK_DFRN), intval($aes_allow));
                 }
                 if ($r) {
                     info(t("Introduction complete.") . EOL);
                 }
                 /**
                  * Allow the blocked remote notification to complete
                  */
                 if (is_array($contact_record)) {
                     $dfrn_request = $contact_record['request'];
                 }
                 if (strlen($dfrn_request) && strlen($confirm_key)) {
                     $s = fetch_url($dfrn_request . '?confirm_key=' . $confirm_key);
                 }
                 // (ignore reply, nothing we can do it failed)
                 goaway($dfrn_url);
                 return;
                 // NOTREACHED
             }
         }
         // invalid/bogus request
         notice(t('Unrecoverable protocol error.') . EOL);
         goaway(z_root());
         return;
         // NOTREACHED
     }
     /**
      * Otherwise:
      * 
      * Scenario 1:
      * We are the requestee. A person from a remote cell has made an introduction 
      * on our profile web page and clicked submit. We will use their DFRN-URL to 
      * figure out how to contact their cell.  
      *
      * Scrape the originating DFRN-URL for everything we need. Create a contact record
      * and an introduction to show our user next time he/she logs in.
      * Finally redirect back to the requestor so that their site can record the request.
      * If our user (the requestee) later confirms this request, a record of it will need 
      * to exist on the requestor's cell in order for the confirmation process to complete.. 
      *
      * It's possible that neither the requestor or the requestee are logged in at the moment,
      * and the requestor does not yet have any credentials to the requestee profile.
      *
      * Who is the requestee? We've already loaded their profile which means their nickname should be
      * in $a->argv[1] and we should have their complete info in $a->profile.
      *
      */
     if (!(is_array($a->profile) && count($a->profile))) {
         notice(t('Profile unavailable.') . EOL);
         return;
     }
     $nickname = $a->profile['nickname'];
     $notify_flags = $a->profile['notify-flags'];
     $uid = $a->profile['uid'];
     $maxreq = intval($a->profile['maxreq']);
     $contact_record = null;
     $failed = false;
     $parms = null;
     if (x($_POST, 'dfrn_url')) {
         /**
          * Block friend request spam
          */
         if ($maxreq) {
             $r = q("SELECT * FROM `intro` WHERE `datetime` > '%s' AND `uid` = %d", dbesc(datetime_convert('UTC', 'UTC', 'now - 24 hours')), intval($uid));
             if (count($r) > $maxreq) {
                 notice(sprintf(t('%s has received too many connection requests today.'), $a->profile['name']) . EOL);
                 notice(t('Spam protection measures have been invoked.') . EOL);
                 notice(t('Friends are advised to please try again in 24 hours.') . EOL);
                 return;
             }
         }
         /**
          *
          * Cleanup old introductions that remain blocked. 
          * Also remove the contact record, but only if there is no existing relationship
          * Do not remove email contacts as these may be awaiting email verification
          */
         $r = q("SELECT `intro`.*, `intro`.`id` AS `iid`, `contact`.`id` AS `cid`, `contact`.`rel` \n\t\t\tFROM `intro` LEFT JOIN `contact` on `intro`.`contact-id` = `contact`.`id`\n\t\t\tWHERE `intro`.`blocked` = 1 AND `contact`.`self` = 0 \n\t\t\tAND `contact`.`network` != '%s'\n\t\t\tAND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 30 MINUTE ", dbesc(NETWORK_MAIL));
         if (count($r)) {
             foreach ($r as $rr) {
                 if (!$rr['rel']) {
                     q("DELETE FROM `contact` WHERE `id` = %d LIMIT 1", intval($rr['cid']));
                 }
                 q("DELETE FROM `intro` WHERE `id` = %d LIMIT 1", intval($rr['iid']));
             }
         }
         /**
          *
          * Cleanup any old email intros - which will have a greater lifetime
          */
         $r = q("SELECT `intro`.*, `intro`.`id` AS `iid`, `contact`.`id` AS `cid`, `contact`.`rel` \n\t\t\tFROM `intro` LEFT JOIN `contact` on `intro`.`contact-id` = `contact`.`id`\n\t\t\tWHERE `intro`.`blocked` = 1 AND `contact`.`self` = 0 \n\t\t\tAND `contact`.`network` = '%s'\n\t\t\tAND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 3 DAY ", dbesc(NETWORK_MAIL));
         if (count($r)) {
             foreach ($r as $rr) {
                 if (!$rr['rel']) {
                     q("DELETE FROM `contact` WHERE `id` = %d LIMIT 1", intval($rr['cid']));
                 }
                 q("DELETE FROM `intro` WHERE `id` = %d LIMIT 1", intval($rr['iid']));
             }
         }
         $url = trim($_POST['dfrn_url']);
         if (!strlen($url)) {
             notice(t("Invalid locator") . EOL);
             return;
         }
         // Canonicalise email-style profile locator
         $hcard = '';
         $url = webfinger_dfrn($url, $hcard);
         if (substr($url, 0, 5) === 'stat:') {
             $network = NETWORK_OSTATUS;
             $url = substr($url, 5);
         } else {
             $network = NETWORK_DFRN;
         }
         logger('dfrn_request: url: ' . $url);
         if (!strlen($url)) {
             notice(t("Unable to resolve your name at the provided location.") . EOL);
             return;
         }
         if ($network === NETWORK_DFRN) {
             $ret = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `self` = 0 LIMIT 1", intval($uid), dbesc($url));
             if (count($ret)) {
                 if (strlen($ret[0]['issued-id'])) {
                     notice(t('You have already introduced yourself here.') . EOL);
                     return;
                 } elseif ($ret[0]['rel'] == CONTACT_IS_FRIEND) {
                     notice(sprintf(t('Apparently you are already friends with %s.'), $a->profile['name']) . EOL);
                     return;
                 } else {
                     $contact_record = $ret[0];
                     $parms = array('dfrn-request' => $ret[0]['request']);
                 }
             }
             $issued_id = random_string();
             if (is_array($contact_record)) {
                 // There is a contact record but no issued-id, so this
                 // is a reciprocal introduction from a known contact
                 $r = q("UPDATE `contact` SET `issued-id` = '%s' WHERE `id` = %d LIMIT 1", dbesc($issued_id), intval($contact_record['id']));
             } else {
                 if (!validate_url($url)) {
                     notice(t('Invalid profile URL.') . EOL);
                     goaway($a->get_baseurl() . '/' . $a->cmd);
                     return;
                     // NOTREACHED
                 }
                 if (!allowed_url($url)) {
                     notice(t('Disallowed profile URL.') . EOL);
                     goaway($a->get_baseurl() . '/' . $a->cmd);
                     return;
                     // NOTREACHED
                 }
                 require_once 'Scrape.php';
                 $parms = scrape_dfrn($hcard ? $hcard : $url);
                 if (!count($parms)) {
                     notice(t('Profile location is not valid or does not contain profile information.') . EOL);
                     goaway($a->get_baseurl() . '/' . $a->cmd);
                 } else {
                     if (!x($parms, 'fn')) {
                         notice(t('Warning: profile location has no identifiable owner name.') . EOL);
                     }
                     if (!x($parms, 'photo')) {
                         notice(t('Warning: profile location has no profile photo.') . EOL);
                     }
                     $invalid = validate_dfrn($parms);
                     if ($invalid) {
                         notice(sprintf(tt("%d required parameter was not found at the given location", "%d required parameters were not found at the given location", $invalid), $invalid) . EOL);
                         return;
                     }
                 }
                 $parms['url'] = $url;
                 $parms['issued-id'] = $issued_id;
                 dbesc_array($parms);
                 $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`,`name`, `nick`, `issued-id`, `photo`, `site-pubkey`,\n\t\t\t\t\t`request`, `confirm`, `notify`, `poll`, `poco`, `network` )\n\t\t\t\t\tVALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", intval($uid), dbesc(datetime_convert()), $parms['url'], dbesc(normalise_link($parms['url'])), $parms['fn'], $parms['nick'], $parms['issued-id'], $parms['photo'], $parms['key'], $parms['dfrn-request'], $parms['dfrn-confirm'], $parms['dfrn-notify'], $parms['dfrn-poll'], $parms['dfrn-poco'], dbesc(NETWORK_DFRN));
                 // find the contact record we just created
                 if ($r) {
                     $r = q("SELECT `id` FROM `contact` \n\t\t\t\t\t\tWHERE `uid` = %d AND `url` = '%s' AND `issued-id` = '%s' LIMIT 1", intval($uid), $parms['url'], $parms['issued-id']);
                     if (count($r)) {
                         $contact_record = $r[0];
                     }
                 }
             }
             if ($r === false) {
                 notice(t('Failed to update contact record.') . EOL);
                 return;
             }
             $hash = random_string() . (string) time();
             // Generate a confirm_key
             if (is_array($contact_record)) {
                 $ret = q("INSERT INTO `intro` ( `uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)\n\t\t\t\t\tVALUES ( %d, %d, 1, %d, '%s', '%s', '%s' )", intval($uid), intval($contact_record['id']), x($_POST, 'knowyou') && $_POST['knowyou'] == 1 ? 1 : 0, dbesc(notags(trim($_POST['dfrn-request-message']))), dbesc($hash), dbesc(datetime_convert()));
             }
             // This notice will only be seen by the requestor if the requestor and requestee are on the same server.
             if (!$failed) {
                 info(t('Your introduction has been sent.') . EOL);
             }
             // "Homecoming" - send the requestor back to their site to record the introduction.
             $dfrn_url = bin2hex($a->get_baseurl() . '/profile/' . $nickname);
             $aes_allow = function_exists('openssl_encrypt') ? 1 : 0;
             goaway($parms['dfrn-request'] . "?dfrn_url={$dfrn_url}" . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . '&confirm_key=' . $hash . ($aes_allow ? "&aes_allow=1" : ""));
             // NOTREACHED
             // END $network === NETWORK_DFRN
         } elseif ($network === NETWORK_OSTATUS) {
             /**
              *
              * OStatus network
              * Check contact existence
              * Try and scrape together enough information to create a contact record, 
              * with us as CONTACT_IS_FOLLOWER
              * Substitute our user's feed URL into $url template
              * Send the subscriber home to subscribe
              *
              */
             $url = str_replace('{uri}', $a->get_baseurl() . '/dfrn_poll/' . $nickname, $url);
             goaway($url);
             // NOTREACHED
             // END $network === NETWORK_OSTATUS
         }
     }
     return;
 }
Example #2
0
function run_submit($url)
{
    global $a;
    if (!strlen($url)) {
        return false;
    }
    logger('Updating: ' . $url);
    //First run a notice script for the site it is hosted on.
    $site_health = notice_site($url, true);
    $submit_start = microtime(true);
    $nurl = str_replace(array('https:', '//www.'), array('http:', '//'), $url);
    $profile_exists = false;
    $r = q("SELECT * FROM `profile` WHERE ( `homepage` = '%s' OR `nurl` = '%s' )", dbesc($url), dbesc($nurl));
    if (count($r)) {
        $profile_exists = true;
        $profile_id = $r[0]['id'];
    }
    //Remove duplicates.
    if (count($r) > 1) {
        for ($i = 1; $i < count($r); $i++) {
            logger('Removed duplicate profile ' . intval($r[$i]['id']));
            q("DELETE FROM `photo` WHERE `profile-id` = %d LIMIT 1", intval($r[$i]['id']));
            q("DELETE FROM `profile` WHERE `id` = %d LIMIT 1", intval($r[$i]['id']));
        }
    }
    require_once 'Scrape.php';
    //Skip the scrape? :D
    $noscrape = $site_health && $site_health['no_scrape_url'];
    if ($noscrape) {
        //Find out who to look up.
        $which = str_replace($site_health['base_url'], '', $url);
        $noscrape = preg_match('~/profile/([^/]+)~', $which, $matches) === 1;
        //If that did not fail...
        if ($noscrape) {
            $parms = noscrape_dfrn($site_health['no_scrape_url'] . '/' . $matches[1]);
            $noscrape = !!$parms;
            //If the result was false, do a scrape after all.
        }
    }
    if (!$noscrape) {
        $parms = scrape_dfrn($url);
    }
    //Empty result is due to an offline site.
    if (!count($parms)) {
        //For large sites this could lower the health too quickly, so don't track health.
        //But for sites that are already in bad status. Do a cleanup now.
        if ($profile_exists && $site_health['health_score'] < $a->config['maintenance']['remove_profile_health_threshold']) {
            logger('Nuked bad health record.');
            nuke_record($url);
        }
        return false;
    } elseif ($parms['explicit-hide'] && $profile_exists) {
        logger('User opted out of the directory.');
        nuke_record($url);
        return true;
        //This is a good update.
    } elseif (validate_dfrn($parms)) {
        return false;
    }
    if (x($parms, 'hide') || !x($parms, 'fn') && x($parms, 'photo')) {
        if ($profile_exists) {
            nuke_record($url);
        }
        return true;
        //This is a good update.
    }
    $photo = $parms['photo'];
    dbesc_array($parms);
    if (x($parms, 'comm')) {
        $parms['comm'] = intval($parms['comm']);
    }
    if ($profile_exists) {
        $r = q("UPDATE `profile` SET \n\t\t\t`name` = '%s', \n\t\t\t`pdesc` = '%s',\n\t\t\t`locality` = '%s', \n\t\t\t`region` = '%s', \n\t\t\t`postal-code` = '%s', \n\t\t\t`country-name` = '%s', \n\t\t\t`gender` = '%s', \n\t\t\t`marital` = '%s', \n\t\t\t`homepage` = '%s',\n\t\t\t`nurl` = '%s',\n\t\t\t`comm` = %d,\n\t\t\t`tags` = '%s',\n\t\t\t`updated` = '%s' \n\t\t\tWHERE `id` = %d LIMIT 1", $parms['fn'], $parms['pdesc'], $parms['locality'], $parms['region'], $parms['postal-code'], $parms['country-name'], $parms['gender'], $parms['marital'], dbesc($url), dbesc($nurl), intval($parms['comm']), $parms['tags'], dbesc(datetime_convert()), intval($profile_id));
        logger('Update returns: ' . $r);
    } else {
        $r = q("INSERT INTO `profile` ( `name`, `pdesc`, `locality`, `region`, `postal-code`, `country-name`, `gender`, `marital`, `homepage`, `nurl`, `comm`, `tags`, `created`, `updated` )\n\t\t\tVALUES ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s' )", $parms['fn'], $parms['pdesc'], $parms['locality'], $parms['region'], $parms['postal-code'], $parms['country-name'], $parms['gender'], $parms['marital'], dbesc($url), dbesc($nurl), intval($parms['comm']), $parms['tags'], dbesc(datetime_convert()), dbesc(datetime_convert()));
        logger('Insert returns: ' . $r);
        $r = q("SELECT `id` FROM `profile` WHERE ( `homepage` = '%s' or `nurl` = '%s' ) order by id asc", dbesc($url), dbesc($nurl));
        if (count($r)) {
            $profile_id = $r[count($r) - 1]['id'];
        }
        if (count($r) > 1) {
            q("DELETE FROM `photo` WHERE `profile-id` = %d LIMIT 1", intval($r[0]['id']));
            q("DELETE FROM `profile` WHERE `id` = %d LIMIT 1", intval($r[0]['id']));
        }
    }
    if ($parms['tags']) {
        $arr = explode(' ', $parms['tags']);
        if (count($arr)) {
            foreach ($arr as $t) {
                $t = strip_tags(trim($t));
                $t = substr($t, 0, 254);
                if (strlen($t)) {
                    $r = q("SELECT `id` FROM `tag` WHERE `term` = '%s' and `nurl` = '%s' LIMIT 1", dbesc($t), dbesc($nurl));
                    if (!count($r)) {
                        $r = q("INSERT INTO `tag` (`term`, `nurl`) VALUES ('%s', '%s') ", dbesc($t), dbesc($nurl));
                    }
                }
            }
        }
    }
    $submit_photo_start = microtime(true);
    require_once "Photo.php";
    $photo_failure = false;
    $status = false;
    if ($profile_id) {
        $img_str = fetch_url($photo, true);
        $img = new Photo($img_str);
        if ($img) {
            $img->scaleImageSquare(80);
            $r = $img->store($profile_id);
        }
        $r = q("UPDATE `profile` SET `photo` = '%s' WHERE `id` = %d LIMIT 1", dbesc($a->get_baseurl() . '/photo/' . $profile_id . '.jpg'), intval($profile_id));
        $status = true;
    } else {
        nuke_record($url);
        return false;
    }
    $submit_end = microtime(true);
    $photo_time = round(($submit_end - $submit_photo_start) * 1000);
    $time = round(($submit_end - $submit_start) * 1000);
    //Record the scrape speed in a scrapes table.
    if ($site_health && $status) {
        q("INSERT INTO `site-scrape` (`site_health_id`, `dt_performed`, `request_time`, `scrape_time`, `photo_time`, `total_time`)" . "VALUES (%u, NOW(), %u, %u, %u, %u)", $site_health['id'], $parms['_timings']['fetch'], $parms['_timings']['scrape'], $photo_time, $time);
    }
    return $status;
}