예제 #1
0
/**
 * @brief
 *
 * @param array $argv
 * @param array $argc
 */
function directory_run($argv, $argc)
{
    cli_startup();
    if ($argc < 2) {
        return;
    }
    $force = false;
    $pushall = true;
    if ($argc > 2) {
        if ($argv[2] === 'force') {
            $force = true;
        }
        if ($argv[2] === 'nopush') {
            $pushall = false;
        }
    }
    logger('directory update', LOGGER_DEBUG);
    $dirmode = get_config('system', 'directory_mode');
    if ($dirmode === false) {
        $dirmode = DIRECTORY_MODE_NORMAL;
    }
    $x = q("select * from channel where channel_id = %d limit 1", intval($argv[1]));
    if (!$x) {
        return;
    }
    $channel = $x[0];
    if ($dirmode != DIRECTORY_MODE_NORMAL) {
        // this is an in-memory update and we don't need to send a network packet.
        local_dir_update($argv[1], $force);
        q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
        // Now update all the connections
        if ($pushall) {
            proc_run('php', 'include/notifier.php', 'refresh_all', $channel['channel_id']);
        }
        return;
    }
    // otherwise send the changes upstream
    $directory = find_upstream_directory($dirmode);
    $url = $directory['url'] . '/post';
    // ensure the upstream directory is updated
    $packet = zot_build_packet($channel, $force ? 'force_refresh' : 'refresh');
    $z = zot_zot($url, $packet);
    // re-queue if unsuccessful
    if (!$z['success']) {
        /** @FIXME we aren't updating channel_dirdate if we have to queue
         * the directory packet. That means we'll try again on the next poll run.
         */
        $hash = random_string();
        q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) \n\t\t\tvalues ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc('zot'), dbesc($url), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($packet), dbesc(''));
    } else {
        q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
    }
    // Now update all the connections
    if ($pushall) {
        proc_run('php', 'include/notifier.php', 'refresh_all', $channel['channel_id']);
    }
}
예제 #2
0
 public static function run($argc, $argv)
 {
     if ($argc < 2) {
         return;
     }
     $force = false;
     $pushall = true;
     if ($argc > 2) {
         if ($argv[2] === 'force') {
             $force = true;
         }
         if ($argv[2] === 'nopush') {
             $pushall = false;
         }
     }
     logger('directory update', LOGGER_DEBUG);
     $dirmode = get_config('system', 'directory_mode');
     if ($dirmode === false) {
         $dirmode = DIRECTORY_MODE_NORMAL;
     }
     $x = q("select * from channel where channel_id = %d limit 1", intval($argv[1]));
     if (!$x) {
         return;
     }
     $channel = $x[0];
     if ($dirmode != DIRECTORY_MODE_NORMAL) {
         // this is an in-memory update and we don't need to send a network packet.
         local_dir_update($argv[1], $force);
         q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
         // Now update all the connections
         if ($pushall) {
             Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
         }
         return;
     }
     // otherwise send the changes upstream
     $directory = find_upstream_directory($dirmode);
     $url = $directory['url'] . '/post';
     // ensure the upstream directory is updated
     $packet = zot_build_packet($channel, $force ? 'force_refresh' : 'refresh');
     $z = zot_zot($url, $packet);
     // re-queue if unsuccessful
     if (!$z['success']) {
         /** @FIXME we aren't updating channel_dirdate if we have to queue
          * the directory packet. That means we'll try again on the next poll run.
          */
         $hash = random_string();
         queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'posturl' => $url, 'notify' => $packet));
     } else {
         q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
     }
     // Now update all the connections
     if ($pushall) {
         Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
     }
 }
예제 #3
0
파일: queue.php 프로젝트: Mauru/red
function queue_run($argv, $argc)
{
    cli_startup();
    global $a;
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if (argc() > 1) {
        $queue_id = argv(1);
    } else {
        $queue_id = 0;
    }
    $deadguys = array();
    logger('queue: start');
    $r = q("DELETE FROM outq WHERE outq_created < UTC_TIMESTAMP() - INTERVAL 3 DAY");
    if ($queue_id) {
        $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1", dbesc($queue_id));
    } else {
        // For the first 12 hours we'll try to deliver every 15 minutes
        // After that, we'll only attempt delivery once per hour.
        // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
        // so that we don't start off a thousand deliveries for a couple of dead hubs.
        // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
        // Other drivers will have to do something different here and may need their own query.
        $r = q("SELECT * FROM outq WHERE outq_delivered = 0 and (( outq_created > UTC_TIMESTAMP() - INTERVAL 12 HOUR and outq_updated < UTC_TIMESTAMP() - INTERVAL 15 MINUTE ) OR ( outq_updated < UTC_TIMESTAMP() - INTERVAL 1 HOUR )) group by outq_posturl");
    }
    if (!$r) {
        return;
    }
    foreach ($r as $rr) {
        if (in_array($rr['outq_posturl'], $deadguys)) {
            continue;
        }
        if ($rr['outq_driver'] === 'post') {
            $result = z_post_url($rr['outq_posturl'], $rr['outq_msg']);
            if ($result['success'] && $result['return_code'] < 300) {
                logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("delete from outq where outq_hash = '%s' limit 1", dbesc($rr['ouq_hash']));
            } else {
                logger('queue: queue post returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
            }
            continue;
        }
        $result = zot_zot($rr['outq_posturl'], $rr['outq_notify']);
        if ($result['success']) {
            zot_process_response($rr['outq_posturl'], $result, $rr);
        } else {
            $deadguys[] = $rr['outq_posturl'];
            $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
        }
    }
}
예제 #4
0
 function get()
 {
     // This is just a test utility function and may go away once we build these tools into
     // the address book and directory to do dead site discovery.
     // The response packet include the current URL and key so we can discover if the server
     // has been re-installed and clean up (e.g. get rid of) any old hublocs and xchans.
     // Remember to add '/post' to the url
     if (!local_channel()) {
         return;
     }
     $url = $_REQUEST['url'];
     if (!$url) {
         return;
     }
     $m = zot_build_packet(\App::get_channel(), 'ping');
     $r = zot_zot($url, $m);
     return print_r($r, true);
 }
예제 #5
0
파일: deliver.php 프로젝트: Mauru/red
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("delete from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post') {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                // If there is no outq_msg, this is a refresh_all message which does not require local handling
                if ($r[0]['outq_msg']) {
                    $msg = array('body' => json_encode(array('pickup' => array(array('notify' => json_decode($r[0]['outq_notify'], true), 'message' => json_decode($r[0]['outq_msg'], true))))));
                    zot_import($msg, z_root());
                    $r = q("delete from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
예제 #6
0
 function admin_page_hubloc_post(&$a)
 {
     check_form_security_token_redirectOnErr('/admin/hubloc', 'admin_hubloc');
     require_once 'include/zot.php';
     //prepare for ping
     if ($_POST['hublocid']) {
         $hublocid = $_POST['hublocid'];
         $arrhublocurl = q("SELECT hubloc_url FROM hubloc WHERE hubloc_id = %d ", intval($hublocid));
         $hublocurl = $arrhublocurl[0]['hubloc_url'] . '/post';
         //perform ping
         $m = zot_build_packet(\App::get_channel(), 'ping');
         $r = zot_zot($hublocurl, $m);
         //handle results and set the hubloc flags in db to make results visible
         $r2 = $r['body'];
         $r3 = $r2['success'];
         if ($r3['success'] == True) {
             //set HUBLOC_OFFLINE to 0
             logger(' success = true ', LOGGER_DEBUG);
         } else {
             //set HUBLOC_OFFLINE to 1
             logger(' success = false ', LOGGER_DEBUG);
         }
         //unfotunatly zping wont work, I guess return format is not correct
         //require_once('mod/zping.php');
         //$r = zping_content($hublocurl);
         //logger('zping answer: ' . $r, LOGGER_DEBUG);
         //in case of repair store new pub key for tested hubloc (all channel with this hubloc) in db
         //after repair set hubloc flags to 0
     }
     goaway(z_root() . '/admin/hubloc');
 }
예제 #7
0
파일: Auth.php 프로젝트: BlaBlaNet/hubzilla
 function Verify($channel, $hubloc)
 {
     logger('auth request received from ' . $hubloc['hubloc_addr']);
     $this->remote = remote_channel();
     $this->remote_service_class = '';
     $this->remote_level = 0;
     $this->remote_hub = $hubloc['hubloc_url'];
     $this->dnt = 0;
     // check credentials and access
     // If they are already authenticated and haven't changed credentials,
     // we can save an expensive network round trip and improve performance.
     // Also check that they are coming from the same site as they authenticated with originally.
     $already_authed = remote_channel() && $hubloc['hubloc_hash'] == remote_channel() && $hubloc['hubloc_url'] === $_SESSION['remote_hub'] ? true : false;
     if ($this->delegate && $this->delegate !== $_SESSION['delegate_channel']) {
         $already_authed = false;
     }
     if ($already_authed) {
         return true;
     }
     if (local_channel()) {
         // tell them to logout if they're logged in locally as anything but the target remote account
         // in which case just shut up because they don't need to be doing this at all.
         if (\App::$channel['channel_hash'] == $hubloc['xchan_hash']) {
             return true;
         } else {
             logger('already authenticated locally as somebody else.');
             notice(t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL);
             if ($this->test) {
                 $this->Debug('already logged in locally with a conflicting identity.');
                 return false;
             }
         }
         return false;
     }
     // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the
     // site private key
     // The actual channel sending the packet ($c[0]) is not important, but this provides a
     // generic zot packet with a sender which can be verified
     $p = zot_build_packet($channel, $type = 'auth_check', array(array('guid' => $hubloc['hubloc_guid'], 'guid_sig' => $hubloc['hubloc_guid_sig'])), $hubloc['hubloc_sitekey'], $this->sec);
     $this->Debug('auth check packet created using sitekey ' . $hubloc['hubloc_sitekey']);
     $this->Debug('packet contents: ' . $p);
     $result = zot_zot($hubloc['hubloc_callback'], $p);
     if (!$result['success']) {
         logger('auth_check callback failed.');
         if ($this->test) {
             $this->Debug('auth check request to your site returned .' . print_r($result, true));
         }
         return false;
     }
     $j = json_decode($result['body'], true);
     if (!$j) {
         logger('auth_check json data malformed.');
         if ($this->test) {
             $this->Debug('json malformed: ' . $result['body']);
         }
         return false;
     }
     $this->Debug('auth check request returned .' . print_r($j, true));
     if (!$j['success']) {
         return false;
     }
     // legit response, but we do need to check that this wasn't answered by a man-in-middle
     if (!rsa_verify($this->sec . $hubloc['xchan_hash'], base64url_decode($j['confirm']), $hubloc['xchan_pubkey'])) {
         logger('final confirmation failed.');
         if ($this->test) {
             $this->Debug('final confirmation failed. ' . $sec . print_r($j, true) . print_r($hubloc, true));
         }
         return false;
     }
     if (array_key_exists('service_class', $j)) {
         $this->remote_service_class = $j['service_class'];
     }
     if (array_key_exists('level', $j)) {
         $this->remote_level = $j['level'];
     }
     if (array_key_exists('DNT', $j)) {
         $this->dnt = $j['DNT'];
     }
     // log them in
     if ($this->test) {
         // testing only - return the success result
         $this->test_results['success'] = true;
         $this->Debug('Authentication Success!');
         $this->Finalise();
     }
     $_SESSION['authenticated'] = 1;
     // check for delegation and if all is well, log them in locally with delegation restrictions
     $this->delegate_success = false;
     if ($this->delegate) {
         $r = q("select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", dbesc($this->delegate));
         if ($r && intval($r[0]['channel_id'])) {
             $allowed = perm_is_allowed($r[0]['channel_id'], $hubloc['xchan_hash'], 'delegate');
             if ($allowed) {
                 $_SESSION['delegate_channel'] = $r[0]['channel_id'];
                 $_SESSION['delegate'] = $hubloc['xchan_hash'];
                 $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
                 require_once 'include/security.php';
                 // this will set the local_channel authentication in the session
                 change_channel($r[0]['channel_id']);
                 $this->delegate_success = true;
             }
         }
     }
     if (!$this->delegate_success) {
         // normal visitor (remote_channel) login session credentials
         $_SESSION['visitor_id'] = $hubloc['xchan_hash'];
         $_SESSION['my_url'] = $hubloc['xchan_url'];
         $_SESSION['my_address'] = $this->address;
         $_SESSION['remote_service_class'] = $this->remote_service_class;
         $_SESSION['remote_level'] = $this->remote_level;
         $_SESSION['remote_hub'] = $this->remote_hub;
         $_SESSION['DNT'] = $this->dnt;
     }
     $arr = array('xchan' => $hubloc, 'url' => $this->desturl, 'session' => $_SESSION);
     call_hooks('magic_auth_success', $arr);
     \App::set_observer($hubloc);
     require_once 'include/security.php';
     \App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
     info(sprintf(t('Welcome %s. Remote authentication successful.'), $hubloc['xchan_name']));
     logger('mod_zot: auth success from ' . $hubloc['xchan_addr']);
     $this->success = true;
     return true;
 }
예제 #8
0
function queue_deliver($outq, $immediate = false)
{
    $base = null;
    $h = parse_url($outq['outq_posturl']);
    if ($h) {
        $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
    }
    if ($base && $base !== z_root() && $immediate) {
        $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
        if ($y) {
            if (intval($y[0]['site_dead'])) {
                remove_queue_by_posturl($outq['outq_posturl']);
                logger('dead site ignored ' . $base);
                return;
            }
            if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                update_queue_item($outq['outq_hash'], 10);
                logger('immediate delivery deferred for site ' . $base);
                return;
            }
        } else {
            // zot sites should all have a site record, unless they've been dead for as long as
            // your site has existed. Since we don't know for sure what these sites are,
            // call them unknown
            q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", dbesc($base), dbesc(datetime_convert()), intval($outq['outq_driver'] === 'post' ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN));
        }
    }
    $arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
    call_hooks('queue_deliver', $arr);
    if ($arr['handled']) {
        return;
    }
    // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
    if ($outq['outq_driver'] === 'post') {
        $result = z_post_url($outq['outq_posturl'], $outq['outq_msg']);
        if ($result['success'] && $result['return_code'] < 300) {
            logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
            if ($base) {
                q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", dbesc(datetime_convert()), dbesc($base));
            }
            q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", dbesc('accepted for delivery'), dbesc(datetime_convert()), dbesc($outq['outq_hash']));
            remove_queue_item($outq['outq_hash']);
            // server is responding - see if anything else is going to this destination and is piled up
            // and try to send some more. We're relying on the fact that delivery_loop() results in an
            // immediate delivery otherwise we could get into a queue loop.
            if (!$immediate) {
                $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", dbesc($outq['outq_posturl']));
                $piled_up = array();
                if ($x) {
                    foreach ($x as $xx) {
                        $piled_up[] = $xx['outq_hash'];
                    }
                }
                if ($piled_up) {
                    delivery_loop($piled_up);
                }
            }
        } else {
            logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
            update_queue_item($outq['outq_posturl']);
        }
        return;
    }
    // normal zot delivery
    logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
    $result = zot_zot($outq['outq_posturl'], $outq['outq_notify']);
    if ($result['success']) {
        logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
        zot_process_response($outq['outq_posturl'], $result, $outq);
    } else {
        logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
        logger('deliver: remote zot delivery fail data: ' . print_r($result, true), LOGGER_DATA);
        update_queue_item($outq['outq_hash'], 10);
    }
    return;
}
예제 #9
0
파일: notifier.php 프로젝트: redmatrix/red
function notifier_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    require_once "session.php";
    require_once "datetime.php";
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if ($argc < 3) {
        return;
    }
    logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    $item_id = $argv[2];
    $extra = $argc > 3 ? $argv[3] : null;
    if (!$item_id) {
        return;
    }
    require_once 'include/identity.php';
    $sys = get_sys_channel();
    if ($cmd == 'permission_update') {
        // Get the recipient
        $r = q("select abook.*, hubloc.* from abook \n\t\t\tleft join hubloc on hubloc_hash = abook_xchan\n\t\t\twhere abook_id = %d and not ( abook_flags & %d ) > 0 \n\t\t\tand not (hubloc_flags & %d) > 0  and not (hubloc_status & %d) > 0 limit 1", intval($item_id), intval(ABOOK_FLAG_SELF), intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE));
        if ($r) {
            // Get the sender
            $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($r[0]['abook_channel']));
            if ($s) {
                if ($r[0]['hubloc_network'] === 'diaspora' || $r[0]['hubloc_network'] === 'friendica-over-diaspora') {
                    require_once 'include/diaspora.php';
                    diaspora_share($s[0], $r[0]);
                } else {
                    // send a refresh message to each hub they have registered here
                    $h = q("select * from hubloc where hubloc_hash = '%s' \n\t\t\t\t\t\tand not (hubloc_flags & %d) > 0  and not (hubloc_status & %d) > 0", dbesc($r[0]['hubloc_hash']), intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE));
                    if ($h) {
                        foreach ($h as $hh) {
                            $data = zot_build_packet($s[0], 'refresh', array(array('guid' => $hh['hubloc_guid'], 'guid_sig' => $hh['hubloc_guid_sig'], 'url' => $hh['hubloc_url'])));
                            if ($data) {
                                $result = zot_zot($hh['hubloc_callback'], $data);
                                // if immediate delivery failed, stick it in the queue to try again later.
                                if (!$result['success']) {
                                    $hash = random_string();
                                    q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) \n\t\t\t\t\t\t\t\t\t\tvalues ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($s[0]['channel_account_id']), intval($s[0]['channel_id']), dbesc('zot'), dbesc($hh['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($data), dbesc(''));
                                }
                            }
                        }
                    }
                }
            }
        }
        return;
    }
    $expire = false;
    $request = false;
    $mail = false;
    $fsuggest = false;
    $top_level = false;
    $location = false;
    $recipients = array();
    $url_recipients = array();
    $normal_mode = true;
    $packet_type = 'undefined';
    if ($cmd === 'mail') {
        $normal_mode = false;
        $mail = true;
        $private = true;
        $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!$message) {
            return;
        }
        xchan_mail_query($message[0]);
        $uid = $message[0]['channel_id'];
        $recipients[] = $message[0]['from_xchan'];
        // include clones
        $recipients[] = $message[0]['to_xchan'];
        $item = $message[0];
        $encoded_item = encode_mail($item);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item['channel_id']));
        if ($s) {
            $channel = $s[0];
        }
    } elseif ($cmd === 'request') {
        $channel_id = $item_id;
        $xchan = $argv[3];
        $request_message_id = $argv[4];
        $s = q("select * from channel where channel_id = %d limit 1", intval($channel_id));
        if ($s) {
            $channel = $s[0];
        }
        $private = true;
        $recipients[] = $xchan;
        $packet_type = 'request';
        $normal_mode = false;
    } elseif ($cmd === 'expire') {
        // FIXME
        // This will require a special zot packet containing a list of item message_id's to be expired.
        // This packet will be public, since we cannot selectively deliver here.
        // We need the handling on this end to create the array, and the handling on the remote end
        // to verify permissions (for each item) and process it. Until this is complete, the expire feature will be disabled.
        return;
        $normal_mode = false;
        $expire = true;
        $items = q("SELECT * FROM item WHERE uid = %d AND ( item_flags & %d )>0\n\t\t\tAND ( item_restrict & %d )>0 AND `changed` > %s - INTERVAL %s", intval($item_id), intval(ITEM_WALL), intval(ITEM_DELETED), db_utcnow(), db_quoteinterval('10 MINUTE'));
        $uid = $item_id;
        $item_id = 0;
        if (!$items) {
            return;
        }
    } elseif ($cmd === 'suggest') {
        $normal_mode = false;
        $fsuggest = true;
        $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!count($suggest)) {
            return;
        }
        $uid = $suggest[0]['uid'];
        $recipients[] = $suggest[0]['cid'];
        $item = $suggest[0];
    } elseif ($cmd === 'refresh_all') {
        logger('notifier: refresh_all: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'refresh';
    } elseif ($cmd === 'location') {
        logger('notifier: location: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $encoded_item = array('locations' => zot_encode_locations($channel), 'type' => 'location', 'encoding' => 'zot');
        $target_item = array('aid' => $channel['channel_account_id'], 'uid' => $channel['channel_id']);
        $private = false;
        $packet_type = 'location';
        $location = true;
    } elseif ($cmd === 'purge_all') {
        logger('notifier: purge_all: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'purge';
    } else {
        // Normal items
        // Fetch the target item
        $r = q("SELECT * FROM item WHERE id = %d and parent != 0 LIMIT 1", intval($item_id));
        if (!$r) {
            return;
        }
        xchan_query($r);
        $r = fetch_post_tags($r);
        $target_item = $r[0];
        $deleted_item = false;
        if ($target_item['item_restrict'] & ITEM_DELETED) {
            logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
            $deleted_item = true;
        }
        $unforwardable = ITEM_UNPUBLISHED | ITEM_DELAYED_PUBLISH | ITEM_WEBPAGE | ITEM_BUILDBLOCK | ITEM_PDL;
        if ($target_item['item_restrict'] & $unforwardable) {
            logger('notifier: target item not forwardable: flags ' . $target_item['item_restrict'], LOGGER_DEBUG);
            return;
        }
        $s = q("select * from channel where channel_id = %d limit 1", intval($target_item['uid']));
        if ($s) {
            $channel = $s[0];
        }
        if ($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
            logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}");
            return;
        }
        if ($target_item['id'] == $target_item['parent']) {
            $parent_item = $target_item;
            $top_level_post = true;
        } else {
            // fetch the parent item
            $r = q("SELECT * from item where id = %d order by id asc", intval($target_item['parent']));
            if (!$r) {
                return;
            }
            xchan_query($r);
            $r = fetch_post_tags($r);
            $parent_item = $r[0];
            $top_level_post = false;
        }
        // avoid looping of discover items 12/4/2014
        if ($sys && $parent_item['uid'] == $sys['channel_id']) {
            return;
        }
        $encoded_item = encode_item($target_item);
        // Send comments to the owner to re-deliver to everybody in the conversation
        // We only do this if the item in question originated on this site. This prevents looping.
        // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
        // Relaying should never be initiated on a post that arrived from elsewhere.
        // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
        // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
        // the hostname in the message_id and provides a second (fallback) opinion.
        $relay_to_owner = !$top_level_post && $target_item['item_flags'] & ITEM_ORIGIN && comment_local_origin($target_item) ? true : false;
        $uplink = false;
        // $cmd === 'relay' indicates the owner is sending it to the original recipients
        // don't allow the item in the relay command to relay to owner under any circumstances, it will loop
        logger('notifier: relay_to_owner: ' . ($relay_to_owner ? 'true' : 'false'), LOGGER_DATA);
        logger('notifier: top_level_post: ' . ($top_level_post ? 'true' : 'false'), LOGGER_DATA);
        logger('notifier: target_item_flags: ' . $target_item['item_flags'] . ' ' . ($target_item['item_flags'] & ITEM_ORIGIN ? 'true' : 'false'), LOGGER_DATA);
        // tag_deliver'd post which needs to be sent back to the original author
        if ($cmd === 'uplink' && $parent_item['item_flags'] & ITEM_UPLINK && !$top_level_post) {
            logger('notifier: uplink');
            $uplink = true;
        }
        if (($relay_to_owner || $uplink) && $cmd !== 'relay') {
            logger('notifier: followup relay', LOGGER_DEBUG);
            $recipients = array($uplink ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
            $private = true;
            if (!$encoded_item['flags']) {
                $encoded_item['flags'] = array();
            }
            $encoded_item['flags'][] = 'relay';
        } else {
            logger('notifier: normal distribution', LOGGER_DEBUG);
            if ($cmd === 'relay') {
                logger('notifier: owner relay');
            }
            // if our parent is a tag_delivery recipient, uplink to the original author causing
            // a delivery fork.
            if ($parent_item['item_flags'] & ITEM_UPLINK && !$top_level_post && $cmd !== 'uplink') {
                logger('notifier: uplinking this item');
                proc_run('php', 'include/notifier.php', 'uplink', $item_id);
            }
            $private = false;
            $recipients = collect_recipients($parent_item, $private);
            // FIXME add any additional recipients such as mentions, etc.
            // don't send deletions onward for other people's stuff
            // TODO verify this is needed - copied logic from same place in old code
            if ($target_item['item_restrict'] & ITEM_DELETED && !($target_item['item_flags'] & ITEM_WALL)) {
                logger('notifier: ignoring delete notification for non-wall item');
                return;
            }
        }
    }
    $walltowall = $top_level_post && $channel['xchan_hash'] === $target_item['author_xchan'] ? true : false;
    // Generic delivery section, we have an encoded item and recipients
    // Now start the delivery process
    $x = $encoded_item;
    $x['title'] = 'private';
    $x['body'] = 'private';
    logger('notifier: encoded item: ' . print_r($x, true), LOGGER_DATA);
    stringify_array_elms($recipients);
    if (!$recipients) {
        return;
    }
    //	logger('notifier: recipients: ' . print_r($recipients,true));
    $env_recips = $private ? array() : null;
    $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',', $recipients) . ")");
    $recip_list = array();
    if ($details) {
        foreach ($details as $d) {
            // If the recipient is federated from a traditional network they won't be able to
            // handle nomadic identity. If we're publishing from a site that they aren't
            // directly connected with, ignore them.
            // FIXME: make sure we run through a notifier loop on the hub they're connected
            // with if this post comes in from a different hub - so that we will deliver to them.
            // On the down side, these channels will stop working if the hub they connected with
            // goes down permanently, as they are (doh) not nomadic.
            if ($d['xchan_instance_url'] && $d['xchan_instance_url'] != z_root()) {
                continue;
            }
            $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
            if ($private) {
                $env_recips[] = array('guid' => $d['xchan_guid'], 'guid_sig' => $d['xchan_guid_sig'], 'hash' => $d['xchan_hash']);
            }
        }
    }
    if ($private && !$env_recips) {
        // shouldn't happen
        logger('notifier: private message with no envelope recipients.' . print_r($argv, true));
    }
    logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list, true), LOGGER_DEBUG);
    // Now we have collected recipients (except for external mentions, FIXME)
    // Let's reduce this to a set of hubs.
    logger('notifier: hub choice: ' . intval($relay_to_owner) . ' ' . intval($private) . ' ' . $cmd, LOGGER_DEBUG);
    // FIXME: I think we need to remove the private bit or this clause will never execute. Needs more coffee to think it through.
    // We may in fact have to send it to clones in case the one we pick recently died.
    if ($relay_to_owner && !$private && $cmd !== 'relay') {
        // If sending a followup to the post owner, only send it to one channel clone - to avoid race conditions.
        // In this case we'll pick the most recently contacted hub, as their primary might be down and the most
        // recently contacted has the best chance of being alive.
        // For private posts or uplinks we have to do things differently as only the sending clone will have the recipient list.
        // We have to send to all clone channels of the owner to find out who has the definitive list. Posts with
        // item_private set (but no ACL list) will return empty recipients (except for the sender and owner) in
        // collect_recipients() above. The end result is we should get only one delivery per delivery chain if we
        // aren't the owner or author.
        $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host from hubloc \n\t\t\twhere hubloc_hash in (" . implode(',', $recipients) . ") order by hubloc_connected desc limit 1");
    } else {
        $r = q("select hubloc_guid, hubloc_url, hubloc_sitekey, hubloc_network, hubloc_flags, hubloc_callback, hubloc_host from hubloc \n\t\t\twhere hubloc_hash in (" . implode(',', $recipients) . ") and not (hubloc_flags & %d) > 0  and not (hubloc_status & %d) > 0", intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE));
    }
    if (!$r) {
        logger('notifier: no hubs');
        return;
    }
    $hubs = $r;
    /**
     * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been 
     * a re-install which has not yet been detected and pruned.
     * For other networks which don't have or require sitekeys, we'll have to use the URL
     */
    $hublist = array();
    // this provides an easily printable list for the logs
    $dhubs = array();
    // delivery hubs where we store our resulting unique array
    $keys = array();
    // array of keys to check uniquness for zot hubs
    $urls = array();
    // array of urls to check uniqueness of hubs from other networks
    foreach ($hubs as $hub) {
        if ($hub['hubloc_network'] == 'zot') {
            if (!in_array($hub['hubloc_sitekey'], $keys)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $keys[] = $hub['hubloc_sitekey'];
            }
        } else {
            if (!in_array($hub['hubloc_url'], $urls)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $urls[] = $hub['hubloc_url'];
            }
        }
    }
    logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist, true), LOGGER_DEBUG);
    $interval = get_config('system', 'delivery_interval') !== false ? intval(get_config('system', 'delivery_interval')) : 2;
    $deliveries_per_process = intval(get_config('system', 'delivery_batch_count'));
    if ($deliveries_per_process <= 0) {
        $deliveries_per_process = 1;
    }
    $deliver = array();
    foreach ($dhubs as $hub) {
        if (defined('DIASPORA_RELIABILITY_EMULATION')) {
            $cointoss = mt_rand(0, 2);
            if ($cointoss == 2) {
                continue;
            }
        }
        if ($hub['hubloc_network'] === 'diaspora' || $hub['hubloc_network'] === 'friendica-over-diaspora') {
            if (!get_config('system', 'diaspora_enabled')) {
                continue;
            }
            require_once 'include/diaspora.php';
            diaspora_process_outbound(array('channel' => $channel, 'env_recips' => $env_recips, 'recipients' => $recipients, 'item' => $item, 'target_item' => $target_item, 'hub' => $hub, 'top_level_post' => $top_level_post, 'private' => $private, 'followup' => $followup, 'relay_to_owner' => $relay_to_owner, 'uplink' => $uplink, 'cmd' => $cmd, 'expire' => $expire, 'mail' => $mail, 'location' => $location, 'fsuggest' => $fsuggest, 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, 'walltowall' => $walltowall));
            continue;
        }
        // default: zot protocol
        $hash = random_string();
        if ($packet_type === 'refresh' || $packet_type === 'purge') {
            $n = zot_build_packet($channel, $packet_type);
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(''));
        } elseif ($packet_type === 'request') {
            $n = zot_build_packet($channel, 'request', $env_recips, $hub['hubloc_sitekey'], $hash, array('message_id' => $request_message_id));
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(''));
        } else {
            $n = zot_build_packet($channel, 'notify', $env_recips, $private ? $hub['hubloc_sitekey'] : null, $hash);
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($target_item['aid']), intval($target_item['uid']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(json_encode($encoded_item)));
        }
        $deliver[] = $hash;
        if (count($deliver) >= $deliveries_per_process) {
            proc_run('php', 'include/deliver.php', $deliver);
            $deliver = array();
            if ($interval) {
                @time_sleep_until(microtime(true) + (double) $interval);
            }
        }
    }
    // catch any stragglers
    if (count($deliver)) {
        proc_run('php', 'include/deliver.php', $deliver);
    }
    logger('notifier: basic loop complete.', LOGGER_DEBUG);
    if ($normal_mode) {
        call_hooks('notifier_normal', $target_item);
    }
    call_hooks('notifier_end', $target_item);
    logger('notifer: complete.');
    return;
}
예제 #10
0
파일: post.php 프로젝트: Mauru/red
function post_init(&$a)
{
    // Most access to this endpoint is via the post method.
    // Here we will pick out the magic auth params which arrive
    // as a get request, and the only communications to arrive this way.
    /**
     * Magic Auth
     * ==========
     *
     * So-called "magic auth" takes place by a special exchange. On the site where the "channel to be authenticated" lives (e.g. $mysite), 
     * a redirection is made via $mysite/magic to the zot endpoint of the remote site ($remotesite) with special GET parameters.
     *
     * The endpoint is typically  https://$remotesite/post - or whatever was specified as the callback url in prior communications
     * (we will bootstrap an address and fetch a zot info packet if possible where no prior communications exist)
     *
     * Four GET parameters are supplied:
     *
     ** auth => the urlencoded webbie (channel@host.domain) of the channel requesting access
     ** dest => the desired destination URL (urlencoded)
     ** sec  => a random string which is also stored on $mysite for use during the verification phase. 
     ** version => the zot revision
     *
     * When this packet is received, an "auth-check" zot message is sent to $mysite.
     * (e.g. if $_GET['auth'] is foobar@podunk.edu, a zot packet is sent to the podunk.edu zot endpoint, which is typically /post)
     * If no information has been recorded about the requesting identity a zot information packet will be retrieved before
     * continuing.
     * 
     * The sender of this packet is an arbitrary/random site channel. The recipients will be a single recipient corresponding
     * to the guid and guid_sig we have associated with the requesting auth identity
     *
     *
     *    {
     *      "type":"auth_check",
     *      "sender":{
     *        "guid":"kgVFf_...",
     *        "guid_sig":"PT9-TApz...",
     *        "url":"http:\/\/podunk.edu",
     *        "url_sig":"T8Bp7j..."
     *      },
     *      "recipients":{
     *        {
     *        "guid":"ZHSqb...",
     *        "guid_sig":"JsAAXi..."
     *        }
     *      }
     *      "callback":"\/post",
     *      "version":1,
     *      "secret":"1eaa661",
     *      "secret_sig":"eKV968b1..."
     *    }
     *
     *
     * auth_check messages MUST use encapsulated encryption. This message is sent to the origination site, which checks the 'secret' to see 
     * if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the 
     * destination channel's private key and base64url encoded. If everything checks out, a json packet is returned:
     *
     *    { 
     *      "success":1, 
     *      "confirm":"q0Ysovd1u..."
     *      "service_class":(optional)
     *      "level":(optional)
     *    }
     *
     * 'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the
     * base64url encoded whirlpool hash of the requestor's guid and guid_sig; signed with the source channel private key. 
     * This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful 
     * verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. 
     * Service_class can be used by cooperating sites to provide different access rights based on account rights and subscription plans. It is 
     * a string whose contents are not defined by protocol. Example: "basic" or "gold". 
     *
     *
     *
     */
    if (array_key_exists('auth', $_REQUEST)) {
        $ret = array('success' => false, 'message' => '');
        logger('mod_zot: auth request received.');
        $address = $_REQUEST['auth'];
        $desturl = $_REQUEST['dest'];
        $sec = $_REQUEST['sec'];
        $version = $_REQUEST['version'];
        $test = x($_REQUEST, 'test') ? intval($_REQUEST['test']) : 0;
        // They are authenticating ultimately to the site and not to a particular channel.
        // Any channel will do, providing it's currently active. We just need to have an
        // identity to attach to the packet we send back. So find one.
        $c = q("select * from channel where not ( channel_pageflags & %d ) limit 1", intval(PAGE_REMOVED));
        if (!$c) {
            // nobody here
            logger('mod_zot: auth: unable to find a response channel');
            if ($test) {
                $ret['message'] .= 'no local channels found.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        // Try and find a hubloc for the person attempting to auth
        $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", dbesc($address));
        if (!$x) {
            // finger them if they can't be found.
            $ret = zot_finger($address, null);
            if ($ret['success']) {
                $j = json_decode($ret['body'], true);
                if ($j) {
                    import_xchan($j);
                }
                $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", dbesc($address));
            }
        }
        if (!$x) {
            logger('mod_zot: auth: unable to finger ' . $address);
            if ($test) {
                $ret['message'] .= 'no hubloc found for ' . $address . ' and probing failed.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        logger('mod_zot: auth request received from ' . $x[0]['hubloc_addr']);
        // check credentials and access
        // If they are already authenticated and haven't changed credentials,
        // we can save an expensive network round trip and improve performance.
        $remote = remote_user();
        $result = null;
        $remote_service_class = '';
        $remote_level = 0;
        $remote_hub = $x[0]['hubloc_url'];
        $DNT = 0;
        // Also check that they are coming from the same site as they authenticated with originally.
        $already_authed = $remote && $x[0]['hubloc_hash'] == $remote && $x[0]['hubloc_url'] === $_SESSION['remote_hub'] ? true : false;
        $j = array();
        if (!$already_authed) {
            // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the site private key
            // The actual channel sending the packet ($c[0]) is not important, but this provides a generic zot packet with a sender
            // which can be verified
            $p = zot_build_packet($c[0], $type = 'auth_check', array(array('guid' => $x[0]['hubloc_guid'], 'guid_sig' => $x[0]['hubloc_guid_sig'])), $x[0]['hubloc_sitekey'], $sec);
            if ($test) {
                $ret['message'] .= 'auth check packet created using sitekey ' . $x[0]['hubloc_sitekey'] . EOL;
                $ret['message'] .= 'packet contents: ' . $p . EOL;
            }
            $result = zot_zot($x[0]['hubloc_callback'], $p);
            if (!$result['success']) {
                logger('mod_zot: auth_check callback failed.');
                if ($test) {
                    $ret['message'] .= 'auth check request to your site returned .' . print_r($result, true) . EOL;
                    json_return_and_die($ret);
                }
                goaway($desturl);
            }
            $j = json_decode($result['body'], true);
            if (!$j) {
                logger('mod_zot: auth_check json data malformed.');
                if ($test) {
                    $ret['message'] .= 'json malformed: ' . $result['body'] . EOL;
                    json_return_and_die($ret);
                }
            }
        }
        if ($test) {
            $ret['message'] .= 'auth check request returned .' . print_r($j, true) . EOL;
        }
        if ($already_authed || $j['success']) {
            if ($j['success']) {
                // legit response, but we do need to check that this wasn't answered by a man-in-middle
                if (!rsa_verify($sec . $x[0]['xchan_hash'], base64url_decode($j['confirm']), $x[0]['xchan_pubkey'])) {
                    logger('mod_zot: auth: final confirmation failed.');
                    if ($test) {
                        $ret['message'] .= 'final confirmation failed. ' . $sec . print_r($j, true) . print_r($x[0], true);
                        json_return_and_die($ret);
                    }
                    goaway($desturl);
                }
                if (array_key_exists('service_class', $j)) {
                    $remote_service_class = $j['service_class'];
                }
                if (array_key_exists('level', $j)) {
                    $remote_level = $j['level'];
                }
                if (array_key_exists('DNT', $j)) {
                    $DNT = $j['DNT'];
                }
            }
            // everything is good... maybe
            if (local_user()) {
                // tell them to logout if they're logged in locally as anything but the target remote account
                // in which case just shut up because they don't need to be doing this at all.
                if ($a->channel['channel_hash'] != $x[0]['xchan_hash']) {
                    logger('mod_zot: auth: already authenticated locally as somebody else.');
                    notice(t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL);
                    if ($test) {
                        $ret['message'] .= 'already logged in locally with a conflicting identity.' . EOL;
                        json_return_and_die($ret);
                    }
                }
                goaway($desturl);
            }
            // log them in
            if ($test) {
                $ret['success'] = true;
                $ret['message'] .= 'Authentication Success!' . EOL;
                json_return_and_die($ret);
            }
            $_SESSION['authenticated'] = 1;
            $_SESSION['visitor_id'] = $x[0]['xchan_hash'];
            $_SESSION['my_url'] = $x[0]['xchan_url'];
            $_SESSION['my_address'] = $address;
            $_SESSION['remote_service_class'] = $remote_service_class;
            $_SESSION['remote_level'] = $remote_level;
            $_SESSION['remote_hub'] = $remote_hub;
            $_SESSION['DNT'] = $DNT;
            $arr = array('xchan' => $x[0], 'url' => $desturl, 'session' => $_SESSION);
            call_hooks('magic_auth_success', $arr);
            $a->set_observer($x[0]);
            require_once 'include/security.php';
            $a->set_groups(init_groups_visitor($_SESSION['visitor_id']));
            info(sprintf(t('Welcome %s. Remote authentication successful.'), $x[0]['xchan_name']));
            logger('mod_zot: auth success from ' . $x[0]['xchan_addr']);
            q("update hubloc set hubloc_status =  (hubloc_status | %d ) where hubloc_id = %d ", intval(HUBLOC_WORKS), intval($x[0]['hubloc_id']));
        } else {
            if ($test) {
                $ret['message'] .= 'auth failure. ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
                json_return_and_die($ret);
            }
            logger('mod_zot: magic-auth failure - not authenticated: ' . $x[0]['xchan_addr']);
            q("update hubloc set hubloc_status =  (hubloc_status | %d ) where hubloc_id = %d ", intval(HUBLOC_RECEIVE_ERROR), intval($x[0]['hubloc_id']));
        }
        // FIXME - we really want to save the return_url in the session before we visit rmagic.
        // This does however prevent a recursion if you visit rmagic directly, as it would otherwise send you back here again.
        // But z_root() probably isn't where you really want to go.
        if ($test) {
            $ret['message'] .= 'auth failure fallthrough ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
            json_return_and_die($ret);
        }
        if (strstr($desturl, z_root() . '/rmagic')) {
            goaway(z_root());
        }
        goaway($desturl);
    }
    return;
}
예제 #11
0
파일: post.php 프로젝트: 23n/hubzilla
/**
 * @brief HTTP POST entry point for Zot.
 *
 * Most access to this endpoint is via the post method.
 * Here we will pick out the magic auth params which arrive as a get request,
 * and the only communications to arrive this way.
 *
 * Magic Auth
 * ==========
 *
 * So-called "magic auth" takes place by a special exchange. On the site where the "channel to be authenticated" lives (e.g. $mysite), 
 * a redirection is made via $mysite/magic to the zot endpoint of the remote site ($remotesite) with special GET parameters.
 *
 * The endpoint is typically  https://$remotesite/post - or whatever was specified as the callback url in prior communications
 * (we will bootstrap an address and fetch a zot info packet if possible where no prior communications exist)
 *
 * Five GET parameters are supplied:
 * * auth => the urlencoded webbie (channel@host.domain) of the channel requesting access
 * * dest => the desired destination URL (urlencoded)
 * * sec  => a random string which is also stored on $mysite for use during the verification phase. 
 * * version => the zot revision
 * * delegate => optional urlencoded webbie of a local channel to invoke delegation rights for
 *
 * When this packet is received, an "auth-check" zot message is sent to $mysite.
 * (e.g. if $_GET['auth'] is foobar@podunk.edu, a zot packet is sent to the podunk.edu zot endpoint, which is typically /post)
 * If no information has been recorded about the requesting identity a zot information packet will be retrieved before
 * continuing.
 *
 * The sender of this packet is an arbitrary/random site channel. The recipients will be a single recipient corresponding
 * to the guid and guid_sig we have associated with the requesting auth identity
 *
 * \code{.json}
 * {
 *   "type":"auth_check",
 *   "sender":{
 *     "guid":"kgVFf_...",
 *     "guid_sig":"PT9-TApz...",
 *     "url":"http:\/\/podunk.edu",
 *     "url_sig":"T8Bp7j..."
 *   },
 *   "recipients":{
 *     {
 *       "guid":"ZHSqb...",
 *       "guid_sig":"JsAAXi..."
 *     }
 *   }
 *   "callback":"\/post",
 *   "version":1,
 *   "secret":"1eaa661",
 *   "secret_sig":"eKV968b1..."
 * }
 * \endcode
 *
 * auth_check messages MUST use encapsulated encryption. This message is sent to the origination site, which checks the 'secret' to see 
 * if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the 
 * destination channel's private key and base64url encoded. If everything checks out, a json packet is returned:
 *
 * \code{.json}
 * {
 *   "success":1,
 *   "confirm":"q0Ysovd1u...",
 *   "service_class":(optional)
 *   "level":(optional)
 * }
 * \endcode
 *
 * 'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the
 * base64url encoded whirlpool hash of the requestor's guid and guid_sig; signed with the source channel private key. 
 * This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful 
 * verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. 
 * Service_class can be used by cooperating sites to provide different access rights based on account rights and subscription plans. It is 
 * a string whose contents are not defined by protocol. Example: "basic" or "gold".
 *
 * @param[in,out] App &$a
 */
function post_init(&$a)
{
    if (array_key_exists('auth', $_REQUEST)) {
        $ret = array('success' => false, 'message' => '');
        logger('mod_zot: auth request received.');
        $address = $_REQUEST['auth'];
        $desturl = $_REQUEST['dest'];
        $sec = $_REQUEST['sec'];
        $version = $_REQUEST['version'];
        $delegate = $_REQUEST['delegate'];
        $test = x($_REQUEST, 'test') ? intval($_REQUEST['test']) : 0;
        // They are authenticating ultimately to the site and not to a particular channel.
        // Any channel will do, providing it's currently active. We just need to have an
        // identity to attach to the packet we send back. So find one.
        $c = q("select * from channel where channel_removed = 0 limit 1");
        if (!$c) {
            // nobody here
            logger('mod_zot: auth: unable to find a response channel');
            if ($test) {
                $ret['message'] .= 'no local channels found.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        // Try and find a hubloc for the person attempting to auth
        $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc", dbesc($address));
        if (!$x) {
            // finger them if they can't be found.
            $ret = zot_finger($address, null);
            if ($ret['success']) {
                $j = json_decode($ret['body'], true);
                if ($j) {
                    import_xchan($j);
                }
                $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc", dbesc($address));
            }
        }
        if (!$x) {
            logger('mod_zot: auth: unable to finger ' . $address);
            if ($test) {
                $ret['message'] .= 'no hubloc found for ' . $address . ' and probing failed.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        foreach ($x as $xx) {
            logger('mod_zot: auth request received from ' . $xx['hubloc_addr']);
            // check credentials and access
            // If they are already authenticated and haven't changed credentials,
            // we can save an expensive network round trip and improve performance.
            $remote = remote_channel();
            $result = null;
            $remote_service_class = '';
            $remote_level = 0;
            $remote_hub = $xx['hubloc_url'];
            $DNT = 0;
            // Also check that they are coming from the same site as they authenticated with originally.
            $already_authed = $remote && $xx['hubloc_hash'] == $remote && $xx['hubloc_url'] === $_SESSION['remote_hub'] ? true : false;
            if ($delegate && $delegate !== $_SESSION['delegate_channel']) {
                $already_authed = false;
            }
            $j = array();
            if (!$already_authed) {
                // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the site private key
                // The actual channel sending the packet ($c[0]) is not important, but this provides a generic zot packet with a sender
                // which can be verified
                $p = zot_build_packet($c[0], $type = 'auth_check', array(array('guid' => $xx['hubloc_guid'], 'guid_sig' => $xx['hubloc_guid_sig'])), $xx['hubloc_sitekey'], $sec);
                if ($test) {
                    $ret['message'] .= 'auth check packet created using sitekey ' . $xx['hubloc_sitekey'] . EOL;
                    $ret['message'] .= 'packet contents: ' . $p . EOL;
                }
                $result = zot_zot($xx['hubloc_callback'], $p);
                if (!$result['success']) {
                    logger('mod_zot: auth_check callback failed.');
                    if ($test) {
                        $ret['message'] .= 'auth check request to your site returned .' . print_r($result, true) . EOL;
                        continue;
                    }
                    continue;
                }
                $j = json_decode($result['body'], true);
                if (!$j) {
                    logger('mod_zot: auth_check json data malformed.');
                    if ($test) {
                        $ret['message'] .= 'json malformed: ' . $result['body'] . EOL;
                        continue;
                    }
                }
            }
            if ($test) {
                $ret['message'] .= 'auth check request returned .' . print_r($j, true) . EOL;
            }
            if ($already_authed || $j['success']) {
                if ($j['success']) {
                    // legit response, but we do need to check that this wasn't answered by a man-in-middle
                    if (!rsa_verify($sec . $xx['xchan_hash'], base64url_decode($j['confirm']), $xx['xchan_pubkey'])) {
                        logger('mod_zot: auth: final confirmation failed.');
                        if ($test) {
                            $ret['message'] .= 'final confirmation failed. ' . $sec . print_r($j, true) . print_r($xx, true);
                            continue;
                        }
                        continue;
                    }
                    if (array_key_exists('service_class', $j)) {
                        $remote_service_class = $j['service_class'];
                    }
                    if (array_key_exists('level', $j)) {
                        $remote_level = $j['level'];
                    }
                    if (array_key_exists('DNT', $j)) {
                        $DNT = $j['DNT'];
                    }
                }
                // everything is good... maybe
                if (local_channel()) {
                    // tell them to logout if they're logged in locally as anything but the target remote account
                    // in which case just shut up because they don't need to be doing this at all.
                    if ($a->channel['channel_hash'] != $xx['xchan_hash']) {
                        logger('mod_zot: auth: already authenticated locally as somebody else.');
                        notice(t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL);
                        if ($test) {
                            $ret['message'] .= 'already logged in locally with a conflicting identity.' . EOL;
                            continue;
                        }
                    }
                    continue;
                }
                // log them in
                if ($test) {
                    $ret['success'] = true;
                    $ret['message'] .= 'Authentication Success!' . EOL;
                    json_return_and_die($ret);
                }
                $delegation_success = false;
                if ($delegate) {
                    $r = q("select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", dbesc($delegate));
                    if ($r && intval($r[0]['channel_id'])) {
                        $allowed = perm_is_allowed($r[0]['channel_id'], $xx['xchan_hash'], 'delegate');
                        if ($allowed) {
                            $_SESSION['delegate_channel'] = $r[0]['channel_id'];
                            $_SESSION['delegate'] = $xx['xchan_hash'];
                            $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
                            require_once 'include/security.php';
                            change_channel($r[0]['channel_id']);
                            $delegation_success = true;
                        }
                    }
                }
                $_SESSION['authenticated'] = 1;
                if (!$delegation_success) {
                    $_SESSION['visitor_id'] = $xx['xchan_hash'];
                    $_SESSION['my_url'] = $xx['xchan_url'];
                    $_SESSION['my_address'] = $address;
                    $_SESSION['remote_service_class'] = $remote_service_class;
                    $_SESSION['remote_level'] = $remote_level;
                    $_SESSION['remote_hub'] = $remote_hub;
                    $_SESSION['DNT'] = $DNT;
                }
                $arr = array('xchan' => $xx, 'url' => $desturl, 'session' => $_SESSION);
                call_hooks('magic_auth_success', $arr);
                $a->set_observer($xx);
                require_once 'include/security.php';
                $a->set_groups(init_groups_visitor($_SESSION['visitor_id']));
                info(sprintf(t('Welcome %s. Remote authentication successful.'), $xx['xchan_name']));
                logger('mod_zot: auth success from ' . $xx['xchan_addr']);
            } else {
                if ($test) {
                    $ret['message'] .= 'auth failure. ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
                    continue;
                }
                logger('mod_zot: magic-auth failure - not authenticated: ' . $xx['xchan_addr']);
            }
            if ($test) {
                $ret['message'] .= 'auth failure fallthrough ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
                continue;
            }
        }
        /**
         * @FIXME we really want to save the return_url in the session before we
         * visit rmagic. This does however prevent a recursion if you visit
         * rmagic directly, as it would otherwise send you back here again.
         * But z_root() probably isn't where you really want to go.
         */
        if (strstr($desturl, z_root() . '/rmagic')) {
            goaway(z_root());
        }
        if ($test) {
            json_return_and_die($ret);
        }
        goaway($desturl);
    }
}
예제 #12
0
function notifier_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    require_once "session.php";
    require_once "datetime.php";
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if ($argc < 3) {
        return;
    }
    logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    $item_id = $argv[2];
    $extra = $argc > 3 ? $argv[3] : null;
    if (!$item_id) {
        return;
    }
    require_once 'include/identity.php';
    $sys = get_sys_channel();
    if ($cmd == 'permission_update') {
        // Get the recipient
        $r = q("select abook.*, hubloc.* from abook \n\t\t\tleft join hubloc on hubloc_hash = abook_xchan\n\t\t\twhere abook_id = %d and abook_self = 0\n\t\t\tand not (hubloc_flags & %d) > 0  and not (hubloc_status & %d) > 0 limit 1", intval($item_id), intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE));
        if ($r) {
            // Get the sender
            $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($r[0]['abook_channel']));
            if ($s) {
                $perm_update = array('sender' => $s[0], 'recipient' => $r[0], 'success' => false);
                call_hooks('permissions_update', $perm_update);
                if (!$perm_update['success']) {
                    // send a refresh message to each hub they have registered here
                    $h = q("select * from hubloc where hubloc_hash = '%s' \n\t\t\t\t\t\tand not (hubloc_flags & %d) > 0  and not (hubloc_status & %d) > 0", dbesc($r[0]['hubloc_hash']), intval(HUBLOC_FLAGS_DELETED), intval(HUBLOC_OFFLINE));
                    if ($h) {
                        foreach ($h as $hh) {
                            $data = zot_build_packet($s[0], 'refresh', array(array('guid' => $hh['hubloc_guid'], 'guid_sig' => $hh['hubloc_guid_sig'], 'url' => $hh['hubloc_url'])));
                            if ($data) {
                                $result = zot_zot($hh['hubloc_callback'], $data);
                                // if immediate delivery failed, stick it in the queue to try again later.
                                if (!$result['success']) {
                                    $hash = random_string();
                                    q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) \n\t\t\t\t\t\t\t\t\t\tvalues ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($s[0]['channel_account_id']), intval($s[0]['channel_id']), dbesc('zot'), dbesc($hh['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($data), dbesc(''));
                                }
                            }
                        }
                    }
                }
            }
        }
        return;
    }
    $expire = false;
    $request = false;
    $mail = false;
    $fsuggest = false;
    $top_level = false;
    $location = false;
    $recipients = array();
    $url_recipients = array();
    $normal_mode = true;
    $packet_type = 'undefined';
    if ($cmd === 'mail') {
        $normal_mode = false;
        $mail = true;
        $private = true;
        $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!$message) {
            return;
        }
        xchan_mail_query($message[0]);
        $uid = $message[0]['channel_id'];
        $recipients[] = $message[0]['from_xchan'];
        // include clones
        $recipients[] = $message[0]['to_xchan'];
        $item = $message[0];
        $encoded_item = encode_mail($item);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item['channel_id']));
        if ($s) {
            $channel = $s[0];
        }
    } elseif ($cmd === 'request') {
        $channel_id = $item_id;
        $xchan = $argv[3];
        $request_message_id = $argv[4];
        $s = q("select * from channel where channel_id = %d limit 1", intval($channel_id));
        if ($s) {
            $channel = $s[0];
        }
        $private = true;
        $recipients[] = $xchan;
        $packet_type = 'request';
        $normal_mode = false;
    } elseif ($cmd === 'expire') {
        // FIXME
        // This will require a special zot packet containing a list of item message_id's to be expired.
        // This packet will be public, since we cannot selectively deliver here.
        // We need the handling on this end to create the array, and the handling on the remote end
        // to verify permissions (for each item) and process it. Until this is complete, the expire feature will be disabled.
        return;
        $normal_mode = false;
        $expire = true;
        $items = q("SELECT * FROM item WHERE uid = %d AND item_wall = 1\n\t\t\tAND item_deleted = 1 AND `changed` > %s - INTERVAL %s", intval($item_id), db_utcnow(), db_quoteinterval('10 MINUTE'));
        $uid = $item_id;
        $item_id = 0;
        if (!$items) {
            return;
        }
    } elseif ($cmd === 'suggest') {
        $normal_mode = false;
        $fsuggest = true;
        $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!count($suggest)) {
            return;
        }
        $uid = $suggest[0]['uid'];
        $recipients[] = $suggest[0]['cid'];
        $item = $suggest[0];
    } elseif ($cmd === 'refresh_all') {
        logger('notifier: refresh_all: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'refresh';
    } elseif ($cmd === 'location') {
        logger('notifier: location: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $encoded_item = array('locations' => zot_encode_locations($channel), 'type' => 'location', 'encoding' => 'zot');
        $target_item = array('aid' => $channel['channel_account_id'], 'uid' => $channel['channel_id']);
        $private = false;
        $packet_type = 'location';
        $location = true;
    } elseif ($cmd === 'purge_all') {
        logger('notifier: purge_all: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'purge';
    } else {
        // Normal items
        // Fetch the target item
        $r = q("SELECT * FROM item WHERE id = %d and parent != 0 LIMIT 1", intval($item_id));
        if (!$r) {
            return;
        }
        xchan_query($r);
        $r = fetch_post_tags($r);
        $target_item = $r[0];
        $deleted_item = false;
        if (intval($target_item['item_deleted'])) {
            logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
            $deleted_item = true;
        }
        if (intval($target_item['item_type']) != ITEM_TYPE_POST) {
            logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
            return;
        }
        if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed_publish'])) {
            logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
            return;
        }
        if (strpos($target_item['postopts'], 'nodeliver') !== false) {
            logger('notifier: target item is undeliverable', LOGGER_DEBUG);
            return;
        }
        $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($target_item['uid']));
        if ($s) {
            $channel = $s[0];
        }
        if ($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
            logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}");
            return;
        }
        if ($target_item['id'] == $target_item['parent']) {
            $parent_item = $target_item;
            $top_level_post = true;
        } else {
            // fetch the parent item
            $r = q("SELECT * from item where id = %d order by id asc", intval($target_item['parent']));
            if (!$r) {
                return;
            }
            if (strpos($r[0]['postopts'], 'nodeliver') !== false) {
                logger('notifier: target item is undeliverable', LOGGER_DEBUG);
                return;
            }
            xchan_query($r);
            $r = fetch_post_tags($r);
            $parent_item = $r[0];
            $top_level_post = false;
        }
        // avoid looping of discover items 12/4/2014
        if ($sys && $parent_item['uid'] == $sys['channel_id']) {
            return;
        }
        $encoded_item = encode_item($target_item);
        // Send comments to the owner to re-deliver to everybody in the conversation
        // We only do this if the item in question originated on this site. This prevents looping.
        // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
        // Relaying should never be initiated on a post that arrived from elsewhere.
        // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
        // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
        // the hostname in the message_id and provides a second (fallback) opinion.
        $relay_to_owner = !$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item) ? true : false;
        $uplink = false;
        // $cmd === 'relay' indicates the owner is sending it to the original recipients
        // don't allow the item in the relay command to relay to owner under any circumstances, it will loop
        logger('notifier: relay_to_owner: ' . ($relay_to_owner ? 'true' : 'false'), LOGGER_DATA);
        logger('notifier: top_level_post: ' . ($top_level_post ? 'true' : 'false'), LOGGER_DATA);
        // tag_deliver'd post which needs to be sent back to the original author
        if ($cmd === 'uplink' && intval($parent_item['item_uplink']) && !$top_level_post) {
            logger('notifier: uplink');
            $uplink = true;
        }
        if (($relay_to_owner || $uplink) && $cmd !== 'relay') {
            logger('notifier: followup relay', LOGGER_DEBUG);
            $recipients = array($uplink ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
            $private = true;
            if (!$encoded_item['flags']) {
                $encoded_item['flags'] = array();
            }
            $encoded_item['flags'][] = 'relay';
        } else {
            logger('notifier: normal distribution', LOGGER_DEBUG);
            if ($cmd === 'relay') {
                logger('notifier: owner relay');
            }
            // if our parent is a tag_delivery recipient, uplink to the original author causing
            // a delivery fork.
            if (intval($parent_item['item_uplink']) && !$top_level_post && $cmd !== 'uplink') {
                logger('notifier: uplinking this item');
                proc_run('php', 'include/notifier.php', 'uplink', $item_id);
            }
            $private = false;
            $recipients = collect_recipients($parent_item, $private);
            // FIXME add any additional recipients such as mentions, etc.
            // don't send deletions onward for other people's stuff
            // TODO verify this is needed - copied logic from same place in old code
            if (intval($target_item['item_deleted']) && !intval($target_item['item_wall'])) {
                logger('notifier: ignoring delete notification for non-wall item');
                return;
            }
        }
    }
    $walltowall = $top_level_post && $channel['xchan_hash'] === $target_item['author_xchan'] ? true : false;
    // Generic delivery section, we have an encoded item and recipients
    // Now start the delivery process
    $x = $encoded_item;
    $x['title'] = 'private';
    $x['body'] = 'private';
    logger('notifier: encoded item: ' . print_r($x, true), LOGGER_DATA);
    stringify_array_elms($recipients);
    if (!$recipients) {
        return;
    }
    //	logger('notifier: recipients: ' . print_r($recipients,true));
    $env_recips = $private ? array() : null;
    $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',', $recipients) . ")");
    $recip_list = array();
    if ($details) {
        foreach ($details as $d) {
            $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
            if ($private) {
                $env_recips[] = array('guid' => $d['xchan_guid'], 'guid_sig' => $d['xchan_guid_sig'], 'hash' => $d['xchan_hash']);
            }
            if ($d['xchan_network'] === 'mail' && $normal_mode) {
                $delivery_options = get_xconfig($d['xchan_hash'], 'system', 'delivery_mode');
                if (!$delivery_options) {
                    format_and_send_email($channel, $d, $target_item);
                }
            }
        }
    }
    if ($private && !$env_recips) {
        // shouldn't happen
        logger('notifier: private message with no envelope recipients.' . print_r($argv, true));
    }
    logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list, true), LOGGER_DEBUG);
    // Now we have collected recipients (except for external mentions, FIXME)
    // Let's reduce this to a set of hubs.
    $r = q("select * from hubloc where hubloc_hash in (" . implode(',', $recipients) . ") \n\t\tand hubloc_error = 0 and hubloc_deleted = 0");
    if (!$r) {
        logger('notifier: no hubs');
        return;
    }
    $hubs = $r;
    $dead_hubs = array();
    $dh = q("select site_url from site where site_dead = 1");
    if (dh) {
        foreach ($dh as $dead) {
            $dead_hubs[] = $dead['site_url'];
        }
    }
    /**
     * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been 
     * a re-install which has not yet been detected and pruned.
     * For other networks which don't have or require sitekeys, we'll have to use the URL
     */
    $hublist = array();
    // this provides an easily printable list for the logs
    $dhubs = array();
    // delivery hubs where we store our resulting unique array
    $keys = array();
    // array of keys to check uniquness for zot hubs
    $urls = array();
    // array of urls to check uniqueness of hubs from other networks
    foreach ($hubs as $hub) {
        if (in_array($hub['hubloc_url'], $dead_hubs)) {
            logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
            continue;
        }
        if ($hub['hubloc_network'] == 'zot') {
            if (!in_array($hub['hubloc_sitekey'], $keys)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $keys[] = $hub['hubloc_sitekey'];
            }
        } else {
            if (!in_array($hub['hubloc_url'], $urls)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $urls[] = $hub['hubloc_url'];
            }
        }
    }
    logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist, true), LOGGER_DEBUG);
    $interval = get_config('system', 'delivery_interval') !== false ? intval(get_config('system', 'delivery_interval')) : 2;
    $deliveries_per_process = intval(get_config('system', 'delivery_batch_count'));
    if ($deliveries_per_process <= 0) {
        $deliveries_per_process = 1;
    }
    $deliveries = array();
    foreach ($dhubs as $hub) {
        if ($hub['hubloc_network'] !== 'zot') {
            $narr = array('channel' => $channel, 'env_recips' => $env_recips, 'recipients' => $recipients, 'item' => $item, 'target_item' => $target_item, 'hub' => $hub, 'top_level_post' => $top_level_post, 'private' => $private, 'followup' => $followup, 'relay_to_owner' => $relay_to_owner, 'uplink' => $uplink, 'cmd' => $cmd, 'expire' => $expire, 'mail' => $mail, 'location' => $location, 'fsuggest' => $fsuggest, 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, 'walltowall' => $walltowall);
            call_hooks('notifier_hub', $narr);
            continue;
        }
        // default: zot protocol
        $hash = random_string();
        if ($packet_type === 'refresh' || $packet_type === 'purge') {
            $n = zot_build_packet($channel, $packet_type);
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(''));
        } elseif ($packet_type === 'request') {
            $n = zot_build_packet($channel, 'request', $env_recips, $hub['hubloc_sitekey'], $hash, array('message_id' => $request_message_id));
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(''));
        } else {
            $n = zot_build_packet($channel, 'notify', $env_recips, $private ? $hub['hubloc_sitekey'] : null, $hash);
            q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($target_item['aid']), intval($target_item['uid']), dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($n), dbesc(json_encode($encoded_item)));
            // only create delivery reports for normal undeleted items
            if (array_key_exists('postopts', $target_item) && !$target_item['item_deleted']) {
                q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", dbesc($target_item['mid']), dbesc($hub['hubloc_host']), dbesc($hub['hubloc_host']), dbesc('queued'), dbesc(datetime_convert()), dbesc($channel['channel_hash']), dbesc($hash));
            }
        }
        $deliveries[] = $hash;
    }
    if ($normal_mode) {
        $x = q("select * from hook where hook = 'notifier_normal'");
        if ($x) {
            proc_run('php', 'deliver_hooks.php', $target_item['id']);
        }
    }
    if ($deliveries) {
        $deliver = array();
        foreach ($deliveries as $d) {
            $deliver[] = $d;
            if (count($deliver) >= $deliveries_per_process) {
                proc_run('php', 'include/deliver.php', $deliver);
                $deliver = array();
                if ($interval) {
                    @time_sleep_until(microtime(true) + (double) $interval);
                }
            }
        }
    }
    // catch any stragglers
    if ($deliver) {
        proc_run('php', 'include/deliver.php', $deliver);
    }
    logger('notifier: basic loop complete.', LOGGER_DEBUG);
    call_hooks('notifier_end', $target_item);
    logger('notifer: complete.');
    return;
}
예제 #13
0
function ping_site($url)
{
    $ret = array('success' => false);
    $sys = get_sys_channel();
    $m = zot_build_packet($sys, 'ping');
    $r = zot_zot($url . '/post', $m);
    if (!$r['success']) {
        $ret['message'] = 'no answer from ' . $url;
        return $ret;
    }
    $packet_result = json_decode($r['body'], true);
    if (!$packet_result['success']) {
        $ret['message'] = 'packet failure from ' . $url;
        return $ret;
    }
    if ($packet_result['success']) {
        $ret['success'] = true;
    } else {
        $ret['message'] = 'unknown error from ' . $url;
    }
    return $ret;
}
예제 #14
0
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            /**
             * Check to see if we have any recent communications with this hub (in the last month).
             * If not, reduce the outq_priority.
             */
            $h = parse_url($r[0]['outq_posturl']);
            if ($h) {
                $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
                if ($base !== z_root()) {
                    $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
                    if ($y) {
                        if (intval($y[0]['site_dead'])) {
                            q("delete from outq where outq_posturl = '%s'", dbesc($r[0]['outq_posturl']));
                            logger('dead site ignored ' . $base);
                            continue;
                        }
                        if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                            q("update outq set outq_priority = %d where outq_hash = '%s'", intval($r[0]['outq_priority'] + 10), dbesc($r[0]['outq_hash']));
                            logger('immediate delivery deferred for site ' . $base);
                            continue;
                        }
                    }
                }
            }
            // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            $notify = json_decode($r[0]['outq_notify'], true);
            // Check if this is a conversation request packet. It won't have outq_msg
            // but will be an encrypted packet - so will need to be handed off to
            // web delivery rather than processed inline.
            $sendtoweb = false;
            if (array_key_exists('iv', $notify) && !$r[0]['outq_msg']) {
                $sendtoweb = true;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post' && !$sendtoweb) {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                if ($r[0]['outq_msg']) {
                    $m = json_decode($r[0]['outq_msg'], true);
                    if (array_key_exists('message_list', $m)) {
                        foreach ($m['message_list'] as $mm) {
                            $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $mm)))));
                            zot_import($msg, z_root());
                        }
                    } else {
                        $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $m)))));
                        zot_import($msg, z_root());
                    }
                    $r = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    logger('deliver: remote zot delivery succeeded to ' . $r[0]['outq_posturl']);
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    logger('deliver: remote zot delivery failed to ' . $r[0]['outq_posturl']);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
예제 #15
0
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $dresult = null;
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            /**
             * Check to see if we have any recent communications with this hub (in the last month).
             * If not, reduce the outq_priority.
             */
            $h = parse_url($r[0]['outq_posturl']);
            if ($h) {
                $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
                if ($base !== z_root()) {
                    $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
                    if ($y) {
                        if (intval($y[0]['site_dead'])) {
                            q("delete from outq where outq_posturl = '%s'", dbesc($r[0]['outq_posturl']));
                            logger('dead site ignored ' . $base);
                            continue;
                        }
                        if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                            q("update outq set outq_priority = %d where outq_hash = '%s'", intval($r[0]['outq_priority'] + 10), dbesc($r[0]['outq_hash']));
                            logger('immediate delivery deferred for site ' . $base);
                            continue;
                        }
                    } else {
                        // zot sites should all have a site record, unless they've been dead for as long as
                        // your site has existed. Since we don't know for sure what these sites are,
                        // call them unknown
                        q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", dbesc($base), dbesc(datetime_convert()), intval($r[0]['outq_driver'] === 'post' ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN));
                    }
                }
            }
            // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", dbesc(datetime_convert()), dbesc($site_url));
                    q("update dreport set status = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", dbesc('accepted for delivery'), dbesc(datetime_convert()), dbesc($argv[$x]));
                    $y = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            $notify = json_decode($r[0]['outq_notify'], true);
            // Check if this is a conversation request packet. It won't have outq_msg
            // but will be an encrypted packet - so will need to be handed off to
            // web delivery rather than processed inline.
            $sendtoweb = false;
            if (array_key_exists('iv', $notify) && !$r[0]['outq_msg']) {
                $sendtoweb = true;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post' && !$sendtoweb) {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                if ($r[0]['outq_msg']) {
                    $m = json_decode($r[0]['outq_msg'], true);
                    if (array_key_exists('message_list', $m)) {
                        foreach ($m['message_list'] as $mm) {
                            $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $mm)))));
                            zot_import($msg, z_root());
                        }
                    } else {
                        $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $m)))));
                        $dresult = zot_import($msg, z_root());
                    }
                    $r = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                    if ($dresult && is_array($dresult)) {
                        foreach ($dresult as $xx) {
                            if (is_array($xx) && array_key_exists('message_id', $xx)) {
                                q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", dbesc($xx['message_id']), dbesc($xx['location']), dbesc($xx['recipient']), dbesc($xx['status']), dbesc(datetime_convert($xx['date'])), dbesc($xx['sender']));
                            }
                        }
                    }
                    q("delete from dreport where dreport_queue = '%s' limit 1", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    logger('deliver: remote zot delivery succeeded to ' . $r[0]['outq_posturl']);
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    logger('deliver: remote zot delivery failed to ' . $r[0]['outq_posturl']);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
예제 #16
0
function queue_run($argv, $argc)
{
    cli_startup();
    global $a;
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if (argc() > 1) {
        $queue_id = argv(1);
    } else {
        $queue_id = 0;
    }
    $deadguys = array();
    logger('queue: start');
    $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY'));
    if ($r) {
        foreach ($r as $rr) {
            $site_url = '';
            $h = parse_url($rr['outq_posturl']);
            $desturl = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
            q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s", dbesc($desturl), db_utcnow(), db_quoteinterval('1 MONTH'));
        }
    }
    $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY'));
    if ($queue_id) {
        $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1", dbesc($queue_id));
    } else {
        // For the first 12 hours we'll try to deliver every 15 minutes
        // After that, we'll only attempt delivery once per hour.
        // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
        // so that we don't start off a thousand deliveries for a couple of dead hubs.
        // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
        // Other drivers will have to do something different here and may need their own query.
        // Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
        // "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
        // or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
        // the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
        // or twice a day.
        // FIXME: can we sort postgres on outq_priority and maintain the 'distinct' ?
        // The order by max(outq_priority) might be a dodgy query because of the group by.
        // The desired result is to return a sequence in the order most likely to be delivered in this run.
        // If a hub has already been sitting in the queue for a few days, they should be delivered last;
        // hence every failure should drop them further down the priority list.
        if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
            $prefix = 'DISTINCT ON (outq_posturl)';
            $suffix = 'ORDER BY outq_posturl';
        } else {
            $prefix = '';
            $suffix = 'GROUP BY outq_posturl ORDER BY max(outq_priority)';
        }
        $r = q("SELECT {$prefix} * FROM outq WHERE outq_delivered = 0 and (( outq_created > %s - INTERVAL %s and outq_updated < %s - INTERVAL %s ) OR ( outq_updated < %s - INTERVAL %s )) {$suffix}", db_utcnow(), db_quoteinterval('12 HOUR'), db_utcnow(), db_quoteinterval('15 MINUTE'), db_utcnow(), db_quoteinterval('1 HOUR'));
    }
    if (!$r) {
        return;
    }
    foreach ($r as $rr) {
        if (in_array($rr['outq_posturl'], $deadguys)) {
            continue;
        }
        if ($rr['outq_driver'] === 'post') {
            $result = z_post_url($rr['outq_posturl'], $rr['outq_msg']);
            if ($result['success'] && $result['return_code'] < 300) {
                logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("delete from outq where outq_hash = '%s'", dbesc($rr['ouq_hash']));
            } else {
                logger('queue: queue post returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
            }
            continue;
        }
        $result = zot_zot($rr['outq_posturl'], $rr['outq_notify']);
        if ($result['success']) {
            logger('queue: deliver zot success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
            zot_process_response($rr['outq_posturl'], $result, $rr);
        } else {
            $deadguys[] = $rr['outq_posturl'];
            logger('queue: deliver zot returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
            $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
        }
    }
}
예제 #17
0
파일: zot.php 프로젝트: 23n/hubzilla
/**
 * @brief
 *
 * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
 * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site private key.
 * The entire pickup message is encrypted with the remote site's public key.
 * If everything checks out on the remote end, we will receive back a packet containing one or more messages,
 * which will be processed and delivered before this function ultimately returns.
 *
 * @see zot_import()
 *
 * @param array $arr
 *     decrypted and json decoded notify packet from remote site
 * @return array from zot_import()
 */
function zot_fetch($arr)
{
    logger('zot_fetch: ' . print_r($arr, true), LOGGER_DATA);
    $url = $arr['sender']['url'] . $arr['callback'];
    // set $multiple param on zot_gethub() to return all matching hubs
    // This allows us to recover from re-installs when a redundant (but invalid) hubloc for
    // this identity is widely dispersed throughout the network.
    $ret_hubs = zot_gethub($arr['sender'], true);
    if (!$ret_hubs) {
        logger('zot_fetch: no hub: ' . print_r($arr['sender'], true));
        return;
    }
    foreach ($ret_hubs as $ret_hub) {
        $data = array('type' => 'pickup', 'url' => z_root(), 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system', 'prvkey'))), 'callback' => z_root() . '/post', 'secret' => $arr['secret'], 'secret_sig' => base64url_encode(rsa_sign($arr['secret'], get_config('system', 'prvkey'))));
        $datatosend = json_encode(crypto_encapsulate(json_encode($data), $ret_hub['hubloc_sitekey']));
        $fetch = zot_zot($url, $datatosend);
        $result = zot_import($fetch, $arr['sender']['url']);
        if ($result) {
            return $result;
        }
    }
    return;
}
예제 #18
0
/**
 * @brief
 *
 * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
 * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site private key.
 * The entire pickup message is encrypted with the remote site's public key.
 * If everything checks out on the remote end, we will receive back a packet containing one or more messages,
 * which will be processed and delivered before this function ultimately returns.
 *
 * @see zot_import()
 *
 * @param array $arr
 *     decrypted and json decoded notify packet from remote site
 * @return array from zot_import()
 */
function zot_fetch($arr)
{
    logger('zot_fetch: ' . print_r($arr, true), LOGGER_DATA);
    $url = $arr['sender']['url'] . $arr['callback'];
    $ret_hub = zot_gethub($arr['sender']);
    if (!$ret_hub) {
        logger('zot_fetch: no hub: ' . print_r($arr['sender'], true));
        return;
    }
    $data = array('type' => 'pickup', 'url' => z_root(), 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system', 'prvkey'))), 'callback' => z_root() . '/post', 'secret' => $arr['secret'], 'secret_sig' => base64url_encode(rsa_sign($arr['secret'], get_config('system', 'prvkey'))));
    $datatosend = json_encode(crypto_encapsulate(json_encode($data), $ret_hub['hubloc_sitekey']));
    $fetch = zot_zot($url, $datatosend);
    $result = zot_import($fetch, $arr['sender']['url']);
    return $result;
}