示例#1
0
function slapper($owner, $url, $slap)
{
    // does contact have a salmon endpoint?
    if (!strlen($url)) {
        return;
    }
    if (!$owner['channel_prvkey']) {
        logger(sprintf("channel '%s' (%d) does not have a salmon private key. Send failed.", $owner['channel_address'], $owner['channel_id']));
        return;
    }
    logger('slapper called for ' . $url . '. Data: ' . $slap, LOGGER_DATA, LOG_DEBUG);
    // create a magic envelope
    $data = base64url_encode($slap);
    $data_type = 'application/atom+xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $keyhash = base64url_encode(hash('sha256', salmon_key($owner['channel_pubkey'])), true);
    // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['channel_prvkey']));
    $signature2 = base64url_encode(rsa_sign($data . $precomputed, $owner['channel_prvkey']));
    $signature3 = base64url_encode(rsa_sign($data, $owner['channel_prvkey']));
    $salmon_tpl = get_markup_template('magicsig.tpl');
    $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature));
    // slap them
    $redirects = 0;
    $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
    $return_code = $ret['return_code'];
    // check for success, e.g. 2xx
    if ($return_code > 299) {
        logger('compliant salmon failed. Falling back to status.net hack2');
        // Entirely likely that their salmon implementation is
        // non-compliant. Let's try once more, this time only signing
        // the data, without stripping '=' chars
        $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature2));
        $redirects = 0;
        $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
        $return_code = $ret['return_code'];
        if ($return_code > 299) {
            logger('compliant salmon failed. Falling back to status.net hack3');
            // Entirely likely that their salmon implementation is
            // non-compliant. Let's try once more, this time only signing
            // the data, without the precomputed blob
            $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature3));
            $redirects = 0;
            $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
            $return_code = $ret['return_code'];
        }
    }
    logger('slapper for ' . $url . ' returned ' . $return_code);
    if (!$return_code) {
        return -1;
    }
    if ($return_code == 503 && stristr($ret['header'], 'retry-after')) {
        return -1;
    }
    return $return_code >= 200 && $return_code < 300 ? 0 : 1;
}
示例#2
0
/**
 * Some utility functions for processing the Diaspora comment virus.
 *
 */
function diaspora_sign_fields($fields, $prvkey)
{
    if (!$fields) {
        return '';
    }
    $n = array();
    foreach ($fields as $k => $v) {
        if ($k !== 'author_signature' && $k !== 'parent_author_signature') {
            $n[$k] = $v;
        }
    }
    $s = implode($n, ';');
    logger('signing_string: ' . $s);
    return base64_encode(rsa_sign($s, $prvkey));
}
示例#3
0
 function get()
 {
     if (!is_site_admin()) {
         return;
     }
     $o = '';
     $r = q("select * from channel where channel_removed = 0");
     $sitekey = get_config('system', 'pubkey');
     if ($r) {
         foreach ($r as $rr) {
             $found = false;
             $primary_address = '';
             $x = zot_get_hublocs($rr['channel_hash']);
             if ($x) {
                 foreach ($x as $xx) {
                     if ($xx['hubloc_url'] === z_root() && $xx['hubloc_sitekey'] === $sitekey) {
                         $found = true;
                         break;
                     }
                 }
                 if ($found) {
                     $o .= 'Hubloc exists for ' . $rr['channel_name'] . EOL;
                     continue;
                 }
             }
             $y = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", dbesc($rr['channel_hash']));
             if ($y) {
                 $primary_address = $y[0]['xchan_addr'];
             }
             $hub_address = $rr['channel']['channel_address'] . '@' . \App::get_hostname();
             $primary = $hub_address === $primary_address ? 1 : 0;
             if (!$y) {
                 $primary = 1;
             }
             $m = q("delete from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ", dbesc($rr['channel_hash']), dbesc(z_root()));
             // Create a verified hub location pointing to this site.
             $h = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network )\n\t\t\t\t\tvalues ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($rr['channel_guid']), dbesc($rr['channel_guid_sig']), dbesc($rr['channel_hash']), dbesc($rr['channel_address'] . '@' . \App::get_hostname()), intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $rr['channel_prvkey']))), dbesc(\App::get_hostname()), dbesc(z_root() . '/post'), dbesc($sitekey), dbesc('zot'));
             if ($h) {
                 $o . 'local hubloc created for ' . $rr['channel_name'] . EOL;
             } else {
                 $o .= 'DB update failed for ' . $rr['channel_name'] . EOL;
             }
         }
         return $o;
     }
 }
示例#4
0
function prate_post(&$a)
{
    if (!local_channel()) {
        return;
    }
    $channel = App::get_channel();
    $target = trim($_REQUEST['target']);
    if (!$target) {
        return;
    }
    if ($target === $channel['channel_hash']) {
        return;
    }
    $rating = intval($_POST['rating']);
    if ($rating < -10) {
        $rating = -10;
    }
    if ($rating > 10) {
        $rating = 10;
    }
    $rating_text = trim(escape_tags($_REQUEST['rating_text']));
    $signed = $target . '.' . $rating . '.' . $rating_text;
    $sig = base64url_encode(rsa_sign($signed, $channel['channel_prvkey']));
    $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", dbesc($channel['channel_hash']), dbesc($target));
    if ($z) {
        $record = $z[0]['xlink_id'];
        $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s'\n\t\t\twhere xlink_id = %d", intval($rating), dbesc($rating_text), dbesc($sig), dbesc(datetime_convert()), intval($record));
    } else {
        $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", dbesc($channel['channel_hash']), dbesc($target), intval($rating), dbesc($rating_text), dbesc($sig), dbesc(datetime_convert()));
        $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", dbesc($channel['channel_hash']), dbesc($orig_record[0]['abook_xchan']));
        if ($z) {
            $record = $z[0]['xlink_id'];
        }
    }
    if ($record) {
        proc_run('php', 'include/ratenotif.php', 'rating', $record);
    }
    json_return_and_die(array('result' => true));
}
示例#5
0
 function post()
 {
     if (!local_channel()) {
         return;
     }
     if (!\App::$data['target']) {
         return;
     }
     if (!$_REQUEST['execute']) {
         return;
     }
     $channel = \App::get_channel();
     $rating = intval($_POST['rating']);
     if ($rating < -10) {
         $rating = -10;
     }
     if ($rating > 10) {
         $rating = 10;
     }
     $rating_text = trim(escape_tags($_REQUEST['rating_text']));
     $signed = \App::$data['target'] . '.' . $rating . '.' . $rating_text;
     $sig = base64url_encode(rsa_sign($signed, $channel['channel_prvkey']));
     $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", dbesc($channel['channel_hash']), dbesc(\App::$data['target']));
     if ($z) {
         $record = $z[0]['xlink_id'];
         $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s'\n\t\t\t\twhere xlink_id = %d", intval($rating), dbesc($rating_text), dbesc($sig), dbesc(datetime_convert()), intval($record));
     } else {
         $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", dbesc($channel['channel_hash']), dbesc(\App::$data['target']), intval($rating), dbesc($rating_text), dbesc($sig), dbesc(datetime_convert()));
         $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", dbesc($channel['channel_hash']), dbesc(\App::$data['target']));
         if ($z) {
             $record = $z[0]['xlink_id'];
         }
     }
     if ($record) {
         \Zotlabs\Daemon\Master::Summon(array('Ratenotif', 'rating', $record));
     }
 }
示例#6
0
function item_post(&$a)
{
    // This will change. Figure out who the observer is and whether or not
    // they have permission to post here. Else ignore the post.
    if (!local_channel() && !remote_channel() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_channel();
    $channel = null;
    $observer = null;
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_mid = x($_REQUEST, 'parent_mid') ? trim($_REQUEST['parent_mid']) : '';
    $remote_xchan = x($_REQUEST, 'remote_xchan') ? trim($_REQUEST['remote_xchan']) : false;
    $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($remote_xchan));
    if ($r) {
        $remote_observer = $r[0];
    } else {
        $remote_xchan = $remote_observer = false;
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    require_once 'include/identity.php';
    $sys = get_sys_channel();
    if ($sys && $profile_uid && $sys['channel_id'] == $profile_uid && is_site_admin()) {
        $uid = intval($sys['channel_id']);
        $channel = $sys;
        $observer = $sys;
    }
    if (x($_REQUEST, 'dropitems')) {
        require_once 'include/items.php';
        $arr_drop = explode(',', $_REQUEST['dropitems']);
        drop_items($arr_drop);
        $json = array('success' => 1);
        echo json_encode($json);
        killme();
    }
    call_hooks('post_local_start', $_REQUEST);
    //	 logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $consensus = intval($_REQUEST['consensus']);
    // 'origin' (if non-zero) indicates that this network is where the message originated,
    // for the purpose of relaying comments to other conversation members.
    // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
    // If the API is used from another network with its own distribution
    // and deliveries, you may wish to set origin to 0 or false and allow the other
    // network to relay comments.
    // If you are unsure, it is prudent (and important) to leave it unset.
    $origin = $api_source && array_key_exists('origin', $_REQUEST) ? intval($_REQUEST['origin']) : 1;
    // To represent message-ids on other networks - this will create an item_id record
    $namespace = $api_source && array_key_exists('namespace', $_REQUEST) ? strip_tags($_REQUEST['namespace']) : '';
    $remote_id = $api_source && array_key_exists('remote_id', $_REQUEST) ? strip_tags($_REQUEST['remote_id']) : '';
    $owner_hash = null;
    $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : '';
    $created = x($_REQUEST, 'created') ? datetime_convert('UTC', 'UTC', $_REQUEST['created']) : datetime_convert();
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    $categories = x($_REQUEST, 'category') ? escape_tags($_REQUEST['category']) : '';
    $webpage = x($_REQUEST, 'webpage') ? intval($_REQUEST['webpage']) : 0;
    $pagetitle = x($_REQUEST, 'pagetitle') ? escape_tags(urlencode($_REQUEST['pagetitle'])) : '';
    $layout_mid = x($_REQUEST, 'layout_mid') ? escape_tags($_REQUEST['layout_mid']) : '';
    $plink = x($_REQUEST, 'permalink') ? escape_tags($_REQUEST['permalink']) : '';
    $obj_type = x($_REQUEST, 'obj_type') ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE;
    // allow API to bulk load a bunch of imported items with sending out a bunch of posts.
    $nopush = x($_REQUEST, 'nopush') ? intval($_REQUEST['nopush']) : 0;
    /*
     * Check service class limits
     */
    if ($uid && !x($_REQUEST, 'parent') && !x($_REQUEST, 'post_id')) {
        $ret = item_check_service_class($uid, $_REQUEST['webpage'] == ITEM_WEBPAGE ? true : false);
        if (!$ret['success']) {
            notice(t($ret['message']) . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    if ($pagetitle) {
        require_once 'library/urlify/URLify.php';
        $pagetitle = strtolower(URLify::transliterate($pagetitle));
    }
    $item_flags = $item_restrict = 0;
    $route = '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    if ($parent || $parent_mid) {
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($obj_type == ACTIVITY_OBJ_POST) {
            $obj_type = ACTIVITY_OBJ_COMMENT;
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_mid && $uid) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_mid), intval($uid));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            $parent_mid = $r[0]['mid'];
            if ($r[0]['id'] != $r[0]['parent']) {
                $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid));
            }
        }
        if ($r === false || !count($r)) {
            notice(t('Unable to locate original post.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
        // can_comment_on_post() needs info from the following xchan_query
        xchan_query($r);
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        $thr_parent = $parent_mid;
        $route = $parent_item['route'];
    }
    if (!$observer) {
        $observer = $a->get_observer();
    }
    if ($parent) {
        logger('mod_item: item_post parent=' . $parent);
        $can_comment = false;
        if (array_key_exists('owner', $parent_item) && $parent_item['owner']['abook_flags'] & ABOOK_FLAG_SELF) {
            $can_comment = perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_comments');
        } else {
            $can_comment = can_comment_on_post($observer['xchan_hash'], $parent_item);
        }
        if (!$can_comment) {
            notice(t('Permission denied.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    } else {
        if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_wall')) {
            notice(t('Permission denied.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    // is this an edited post?
    $orig_post = null;
    if ($namespace && $remote_id) {
        // It wasn't an internally generated post - see if we've got an item matching this remote service id
        $i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1", dbesc($namespace), dbesc($remote_id));
        if ($i) {
            $post_id = $i[0]['iid'];
        }
    }
    if ($post_id) {
        $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id));
        if (!count($i)) {
            killme();
        }
        $orig_post = $i[0];
    }
    if (!$channel) {
        if ($uid && $uid == $profile_uid) {
            $channel = $a->get_channel();
        } else {
            // posting as yourself but not necessarily to a channel you control
            $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", intval($profile_uid));
            if ($r) {
                $channel = $r[0];
            }
        }
    }
    if (!$channel) {
        logger("mod_item: no channel.");
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    $owner_xchan = null;
    $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($channel['channel_hash']));
    if ($r && count($r)) {
        $owner_xchan = $r[0];
    } else {
        logger("mod_item: no owner.");
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    $walltowall = false;
    $walltowall_comment = false;
    if ($remote_xchan) {
        $observer = $remote_observer;
    }
    if ($observer) {
        logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG);
        // wall-to-wall detection.
        // For top-level posts, if the author and owner are different it's a wall-to-wall
        // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally.
        if ($observer['xchan_name'] != $owner_xchan['xchan_name']) {
            if ($parent_item && ($parent_item['item_flags'] & (ITEM_WALL | ITEM_ORIGIN)) == (ITEM_WALL | ITEM_ORIGIN)) {
                $walltowall_comment = true;
                $walltowall = true;
            }
            if (!$parent) {
                $walltowall = true;
            }
        }
    }
    $public_policy = x($_REQUEST, 'public_policy') ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'], true);
    if ($webpage) {
        $public_policy = '';
    }
    if ($public_policy) {
        $private = 1;
    }
    if ($orig_post) {
        $private = 0;
        // webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
        if ($webpage) {
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        } else {
            $str_group_allow = $orig_post['allow_gid'];
            $str_contact_allow = $orig_post['allow_cid'];
            $str_group_deny = $orig_post['deny_gid'];
            $str_contact_deny = $orig_post['deny_cid'];
            $public_policy = $orig_post['public_policy'];
            $private = $orig_post['item_private'];
        }
        if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) || strlen($public_policy) || $private) {
            $private = 1;
        }
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $app = $orig_post['app'];
        $title = escape_tags(trim($_REQUEST['title']));
        $body = trim($_REQUEST['body']);
        $item_flags = $orig_post['item_flags'];
        // force us to recalculate if we need to obscure this post
        if ($item_flags & ITEM_OBSCURED) {
            $item_flags = $item_flags ^ ITEM_OBSCURED;
        }
        $item_restrict = $orig_post['item_restrict'];
        $postopts = $orig_post['postopts'];
        $created = $orig_post['created'];
        $mid = $orig_post['mid'];
        $parent_mid = $orig_post['parent_mid'];
        $plink = $orig_post['plink'];
    } else {
        // if coming from the API and no privacy settings are set,
        // use the user default permissions - as they won't have
        // been supplied via a form.
        if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) {
            $str_group_allow = $channel['channel_allow_gid'];
            $str_contact_allow = $channel['channel_allow_cid'];
            $str_group_deny = $channel['channel_deny_gid'];
            $str_contact_deny = $channel['channel_deny_cid'];
        } elseif ($walltowall) {
            // use the channel owner's default permissions
            $str_group_allow = $channel['channel_allow_gid'];
            $str_contact_allow = $channel['channel_allow_cid'];
            $str_group_deny = $channel['channel_deny_gid'];
            $str_contact_deny = $channel['channel_deny_cid'];
        } else {
            // use the posted permissions
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        }
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $title = escape_tags(trim($_REQUEST['title']));
        $body = trim($_REQUEST['body']);
        $body .= trim($_REQUEST['attachment']);
        $postopts = '';
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) || strlen($public_policy) ? 1 : 0;
        // If this is a comment, set the permissions from the parent.
        if ($parent_item) {
            $private = 0;
            if ($parent_item['item_private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid']) || strlen($parent_item['public_policy'])) {
                $private = $parent_item['item_private'] ? $parent_item['item_private'] : 1;
            }
            $public_policy = $parent_item['public_policy'];
            $str_contact_allow = $parent_item['allow_cid'];
            $str_group_allow = $parent_item['allow_gid'];
            $str_contact_deny = $parent_item['deny_cid'];
            $str_group_deny = $parent_item['deny_gid'];
            $owner_hash = $parent_item['owner_xchan'];
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    $expires = NULL_DATE;
    if (feature_enabled($profile_uid, 'content_expire')) {
        if (x($_REQUEST, 'expire')) {
            $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']);
            if ($expires <= datetime_convert()) {
                $expires = NULL_DATE;
            }
        }
    }
    $mimetype = notags(trim($_REQUEST['mimetype']));
    if (!$mimetype) {
        $mimetype = 'text/bbcode';
    }
    if ($preview) {
        $body = z_input_filter($profile_uid, $body, $mimetype);
    }
    // Verify ability to use html or php!!!
    $execflag = false;
    if ($mimetype === 'application/x-php') {
        $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", intval($profile_uid));
        if ($z && ($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE || $z[0]['channel_pageflags'] & PAGE_ALLOWCODE)) {
            if ($uid && get_account_id() == $z[0]['account_id']) {
                $execflag = true;
            } else {
                notice(t('Executable content type not permitted to this channel.') . EOL);
                if (x($_REQUEST, 'return')) {
                    goaway($a->get_baseurl() . "/" . $return_path);
                }
                killme();
            }
        }
    }
    if ($mimetype === 'text/bbcode') {
        require_once 'include/text.php';
        if ($uid && $uid == $profile_uid && feature_enabled($uid, 'markdown')) {
            require_once 'include/bb2diaspora.php';
            $body = escape_tags($body);
            $body = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_shield', $body);
            $body = diaspora2bb($body, true);
            $body = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_unshield', $body);
        }
        // BBCODE alert: the following functions assume bbcode input
        // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
        // we may need virtual or template classes to implement the possible alternatives
        // Work around doubled linefeeds in Tinymce 3.5b2
        // First figure out if it's a status post that would've been
        // created using tinymce. Otherwise leave it alone.
        $plaintext = true;
        //		$plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true);
        //		if((! $parent) && (! $api_source) && (! $plaintext)) {
        //			$body = fix_mce_lf($body);
        //		}
        // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set.
        if (!$parent && get_pconfig($profile_uid, 'system', 'tagifonlyrecip') && substr_count($str_contact_allow, '<') == 1 && $str_group_allow == '' && $str_contact_deny == '' && $str_group_deny == '') {
            $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc(str_replace(array('<', '>'), array('', ''), $str_contact_allow)), intval($profile_uid));
            if ($x && $x[0]['abook_their_perms'] & PERMS_W_TAGWALL) {
                $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n";
            }
        }
        /**
         * fix naked links by passing through a callback to see if this is a red site
         * (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
         * First protect any url inside certain bbcode tags so we don't double link it.
         */
        $body = preg_replace_callback('/\\[code(.*?)\\[\\/(code)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback('/\\[url(.*?)\\[\\/(url)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback('/\\[zrl(.*?)\\[\\/(zrl)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback("/([^\\]\\='" . '"' . "\\/]|^|\\#\\^)(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\@\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", 'red_zrl_callback', $body);
        $body = preg_replace_callback('/\\[\\$b64zrl(.*?)\\[\\/(zrl)\\]/ism', 'red_unescape_codeblock', $body);
        $body = preg_replace_callback('/\\[\\$b64url(.*?)\\[\\/(url)\\]/ism', 'red_unescape_codeblock', $body);
        $body = preg_replace_callback('/\\[\\$b64code(.*?)\\[\\/(code)\\]/ism', 'red_unescape_codeblock', $body);
        // fix any img tags that should be zmg
        $body = preg_replace_callback('/\\[img(.*?)\\](.*?)\\[\\/img\\]/ism', 'red_zrlify_img_callback', $body);
        $body = bb_translate_video($body);
        /**
         * Fold multi-line [code] sequences
         */
        $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body);
        $body = scale_external_images($body, false);
        // Look for tags and linkify them
        $results = linkify_tags($a, $body, $uid ? $uid : $profile_uid);
        if ($results) {
            // Set permissions based on tag replacements
            set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private);
            $post_tags = array();
            foreach ($results as $result) {
                $success = $result['success'];
                if ($success['replaced']) {
                    $post_tags[] = array('uid' => $profile_uid, 'type' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url']);
                }
            }
        }
        /**
         *
         * When a photo was uploaded into the message using the (profile wall) ajax 
         * uploader, The permissions are initially set to disallow anybody but the
         * owner from seeing it. This is because the permissions may not yet have been
         * set for the post. If it's private, the photo permissions should be set
         * appropriately. But we didn't know the final permissions on the post until
         * now. So now we'll look for links of uploaded photos and attachments that are in the
         * post and set them to the same permissions as the post itself.
         *
         * If the post was end-to-end encrypted we can't find images and attachments in the body,
         * use our media_str input instead which only contains these elements - but only do this
         * when encrypted content exists because the photo/attachment may have been removed from 
         * the post and we should keep it private. If it's encrypted we have no way of knowing
         * so we'll set the permissions regardless and realise that the media may not be 
         * referenced in the post. 
         *
         * What is preventing us from being able to upload photos into comments is dealing with
         * the photo and attachment permissions, since we don't always know who was in the 
         * distribution for the top level post.
         * 
         * We might be able to provide this functionality with a lot of fiddling:
         * - if the top level post is public (make the photo public)
         * - if the top level post was written by us or a wall post that belongs to us (match the top level post)
         * - if the top level post has privacy mentions, add those to the permissions.
         * - otherwise disallow the photo *or* make the photo public. This is the part that gets messy. 
         */
        if (!$preview) {
            fix_attached_photo_permissions($profile_uid, $owner_xchan['xchan_hash'], strpos($body, '[/crypt]') ? $_POST['media_str'] : $body, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
            fix_attached_file_permissions($channel, $observer['xchan_hash'], strpos($body, '[/crypt]') ? $_POST['media_str'] : $body, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
        }
        $attachments = '';
        $match = false;
        if (preg_match_all('/(\\[attachment\\](.*?)\\[\\/attachment\\])/', $body, $match)) {
            $attachments = array();
            foreach ($match[2] as $mtch) {
                $hash = substr($mtch, 0, strpos($mtch, ','));
                $rev = intval(substr($mtch, strpos($mtch, ',')));
                $r = attach_by_hash_nodata($hash, $rev);
                if ($r['success']) {
                    $attachments[] = array('href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], 'length' => $r['data']['filesize'], 'type' => $r['data']['filetype'], 'title' => urlencode($r['data']['filename']), 'revision' => $r['data']['revision']);
                }
                $body = str_replace($match[1], '', $body);
            }
        }
    }
    // BBCODE end alert
    if (strlen($categories)) {
        $cats = explode(',', $categories);
        foreach ($cats as $cat) {
            $post_tags[] = array('uid' => $profile_uid, 'type' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)));
        }
    }
    $item_unseen = 1;
    // determine if this is a wall post
    if ($parent) {
        if ($parent_item['item_flags'] & ITEM_WALL) {
            $item_flags = $item_flags | ITEM_WALL;
        }
    } else {
        if (!$webpage) {
            $item_flags = $item_flags | ITEM_WALL;
        }
    }
    if ($origin) {
        $item_flags = $item_flags | ITEM_ORIGIN;
    }
    if ($moderated) {
        $item_restrict = $item_restrict | ITEM_MODERATED;
    }
    if ($webpage) {
        $item_restrict = $item_restrict | $webpage;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    if (!$mid) {
        $mid = $message_id ? $message_id : item_message_id();
    }
    if (!$parent_mid) {
        $parent_mid = $mid;
    }
    if ($parent_item) {
        $parent_mid = $parent_item['mid'];
    }
    // Fallback so that we alway have a thr_parent
    if (!$thr_parent) {
        $thr_parent = $mid;
    }
    $datarray = array();
    if (!$parent) {
        $item_flags = $item_flags | ITEM_THREAD_TOP;
    }
    if ($consensus) {
        $item_flags |= ITEM_CONSENSUS;
    }
    if (!$plink && $item_flags & ITEM_THREAD_TOP) {
        $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
    }
    $datarray['aid'] = $channel['channel_account_id'];
    $datarray['uid'] = $profile_uid;
    $datarray['owner_xchan'] = $owner_hash ? $owner_hash : $owner_xchan['xchan_hash'];
    $datarray['author_xchan'] = $observer['xchan_hash'];
    $datarray['created'] = $created;
    $datarray['edited'] = $orig_post ? datetime_convert() : $created;
    $datarray['expires'] = $expires;
    $datarray['commented'] = $orig_post ? datetime_convert() : $created;
    $datarray['received'] = $orig_post ? datetime_convert() : $created;
    $datarray['changed'] = $orig_post ? datetime_convert() : $created;
    $datarray['mid'] = $mid;
    $datarray['parent_mid'] = $parent_mid;
    $datarray['mimetype'] = $mimetype;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['verb'] = $verb;
    $datarray['obj_type'] = $obj_type;
    $datarray['allow_cid'] = $str_contact_allow;
    $datarray['allow_gid'] = $str_group_allow;
    $datarray['deny_cid'] = $str_contact_deny;
    $datarray['deny_gid'] = $str_group_deny;
    $datarray['item_private'] = $private;
    $datarray['attach'] = $attachments;
    $datarray['thr_parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['item_restrict'] = $item_restrict;
    $datarray['item_flags'] = $item_flags;
    $datarray['layout_mid'] = $layout_mid;
    $datarray['public_policy'] = $public_policy;
    $datarray['comment_policy'] = map_scope($channel['channel_w_comment']);
    $datarray['term'] = $post_tags;
    $datarray['plink'] = $plink;
    $datarray['route'] = $route;
    $datarray['item_unseen'] = $item_unseen;
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $datarray['owner'] = $owner_xchan;
        $datarray['author'] = $observer;
        $datarray['attach'] = json_encode($datarray['attach']);
        $o = conversation($a, array($datarray), 'search', false, 'preview');
        //		logger('preview: ' . $o, LOGGER_DEBUG);
        echo json_encode(array('preview' => $o));
        killme();
    }
    if ($orig_post) {
        $datarray['edit'] = true;
    }
    call_hooks('post_local', $datarray);
    if (x($datarray, 'cancel')) {
        logger('mod_item: post cancelled by plugin.');
        if ($return_path) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        $json = array('cancel' => 1);
        if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
            $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
        }
        echo json_encode($json);
        killme();
    }
    if (mb_strlen($datarray['title']) > 255) {
        $datarray['title'] = mb_substr($datarray['title'], 0, 255);
    }
    if (array_key_exists('item_private', $datarray) && $datarray['item_private']) {
        $datarray['body'] = trim(z_input_filter($datarray['uid'], $datarray['body'], $datarray['mimetype']));
        if ($uid) {
            if ($channel['channel_hash'] === $datarray['author_xchan']) {
                $datarray['sig'] = base64url_encode(rsa_sign($datarray['body'], $channel['channel_prvkey']));
                $datarray['item_flags'] = $datarray['item_flags'] | ITEM_VERIFIED;
            }
        }
        logger('Encrypting local storage');
        $key = get_config('system', 'pubkey');
        $datarray['item_flags'] = $datarray['item_flags'] | ITEM_OBSCURED;
        if ($datarray['title']) {
            $datarray['title'] = json_encode(crypto_encapsulate($datarray['title'], $key));
        }
        if ($datarray['body']) {
            $datarray['body'] = json_encode(crypto_encapsulate($datarray['body'], $key));
        }
    }
    if ($orig_post) {
        $datarray['id'] = $post_id;
        item_store_update($datarray, $execflag);
        update_remote_id($channel, $post_id, $webpage, $pagetitle, $namespace, $remote_id, $mid);
        if (!$nopush) {
            proc_run('php', "include/notifier.php", 'edit_post', $post_id);
        }
        if (x($_REQUEST, 'return') && strlen($return_path)) {
            logger('return: ' . $return_path);
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    } else {
        $post_id = 0;
    }
    $post = item_store($datarray, $execflag);
    $post_id = $post['item_id'];
    if ($post_id) {
        logger('mod_item: saved item ' . $post_id);
        if ($parent) {
            // only send comment notification if this is a wall-to-wall comment,
            // otherwise it will happen during delivery
            if ($datarray['owner_xchan'] != $datarray['author_xchan'] && $parent_item['item_flags'] & ITEM_WALL) {
                notification(array('type' => NOTIFY_COMMENT, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_mid' => $parent_item['mid']));
            }
        } else {
            $parent = $post_id;
            if ($datarray['owner_xchan'] != $datarray['author_xchan']) {
                notification(array('type' => NOTIFY_WALL, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
            }
            if ($uid && $uid == $profile_uid && !$datarray['item_restrict']) {
                q("update channel set channel_lastpost = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($uid));
            }
        }
        // photo comments turn the corresponding item visible to the profile wall
        // This way we don't see every picture in your new photo album posted to your wall at once.
        // They will show up as people comment on them.
        if ($parent_item['item_restrict'] & ITEM_HIDDEN) {
            $r = q("UPDATE `item` SET `item_restrict` = %d WHERE `id` = %d", intval($parent_item['item_restrict'] - ITEM_HIDDEN), intval($parent_item['id']));
        }
    } else {
        logger('mod_item: unable to retrieve post that was just stored.');
        notice(t('System error. Post not saved.') . EOL);
        goaway($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    if ($parent) {
        // Store the comment signature information in case we need to relay to Diaspora
        $ditem = $datarray;
        $ditem['author'] = $observer;
        store_diaspora_comment_sig($ditem, $channel, $parent_item, $post_id, $walltowall_comment ? 1 : 0);
    }
    update_remote_id($channel, $post_id, $webpage, $pagetitle, $namespace, $remote_id, $mid);
    $datarray['id'] = $post_id;
    $datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id;
    call_hooks('post_local_end', $datarray);
    if (!$nopush) {
        proc_run('php', 'include/notifier.php', $notify_type, $post_id);
    }
    logger('post_complete');
    // figure out how to return, depending on from whence we came
    if ($api_source) {
        return $post;
    }
    if ($return_path) {
        goaway($a->get_baseurl() . "/" . $return_path);
    }
    $json = array('success' => 1);
    if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
        $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
    }
    logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
    echo json_encode($json);
    killme();
    // NOTREACHED
}
示例#7
0
文件: text.php 项目: 23n/hubzilla
function item_url_replace($channel, &$item, $old, $new)
{
    if ($item['attach']) {
        json_url_replace($old, $new, $item['attach']);
    }
    if ($item['object']) {
        json_url_replace($old, $new, $item['object']);
    }
    if ($item['target']) {
        json_url_replace($old, $new, $item['target']);
    }
    if (string_replace($old, $new, $item['body'])) {
        $item['sig'] = base64url_encode(rsa_sign($item['body'], $channel['channel_prvkey']));
        $item['item_verified'] = 1;
    }
}
示例#8
0
文件: import.php 项目: Mauru/red
function import_post(&$a)
{
    if (!get_account_id()) {
        return;
    }
    $data = null;
    $seize = x($_REQUEST, 'make_primary') ? intval($_REQUEST['make_primary']) : 0;
    $src = $_FILES['filename']['tmp_name'];
    $filename = basename($_FILES['filename']['name']);
    $filesize = intval($_FILES['filename']['size']);
    $filetype = $_FILES['filename']['type'];
    if ($src) {
        if ($filesize) {
            $data = @file_get_contents($src);
        }
        unlink($src);
    }
    if (!$src) {
        $old_address = x($_REQUEST, 'old_address') ? $_REQUEST['old_address'] : '';
        if (!$old_address) {
            logger('mod_import: nothing to import.');
            notice(t('Nothing to import.') . EOL);
            return;
        }
        $email = x($_REQUEST, 'email') ? $_REQUEST['email'] : '';
        $password = x($_REQUEST, 'password') ? $_REQUEST['password'] : '';
        $channelname = substr($old_address, 0, strpos($old_address, '@'));
        $servername = substr($old_address, strpos($old_address, '@') + 1);
        $scheme = 'https://';
        $api_path = '/api/red/channel/export/basic?f=&channel=' . $channelname;
        $binary = false;
        $redirects = 0;
        $opts = array('http_auth' => $email . ':' . $password);
        $url = $scheme . $servername . $api_path;
        $ret = z_fetch_url($url, $binary, $redirects, $opts);
        if (!$ret['success']) {
            $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts);
        }
        if ($ret['success']) {
            $data = $ret['body'];
        } else {
            notice(t('Unable to download data from old server') . EOL);
        }
    }
    if (!$data) {
        logger('mod_import: empty file.');
        notice(t('Imported file is empty.') . EOL);
        return;
    }
    $data = json_decode($data, true);
    //	logger('import: data: ' . print_r($data,true));
    //	print_r($data);
    // import channel
    $channel = $data['channel'];
    $r = q("select * from channel where (channel_guid = '%s' or channel_hash = '%s' or channel_address = '%s' ) limit 1", dbesc($channel['channel_guid']), dbesc($channel['channel_hash']), dbesc($channel['channel_address']));
    // We should probably also verify the hash
    if ($r) {
        logger('mod_import: duplicate channel. ', print_r($channel, true));
        notice(t('Cannot create a duplicate channel identifier on this system. Import failed.') . EOL);
        return;
    }
    unset($channel['channel_id']);
    $channel['channel_account_id'] = get_account_id();
    $channel['channel_primary'] = $seize ? 1 : 0;
    dbesc_array($channel);
    $r = dbq("INSERT INTO channel (`" . implode("`, `", array_keys($channel)) . "`) VALUES ('" . implode("', '", array_values($channel)) . "')");
    if (!$r) {
        logger('mod_import: channel clone failed. ', print_r($channel, true));
        notice(t('Channel clone failed. Import failed.') . EOL);
        return;
    }
    $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", intval(get_account_id()), $channel['channel_guid']);
    if (!$r) {
        logger('mod_import: channel not found. ', print_r($channel, true));
        notice(t('Cloned channel not found. Import failed.') . EOL);
        return;
    }
    // reset
    $channel = $r[0];
    set_default_login_identity(get_account_id(), $channel['channel_id'], false);
    if ($data['photo']) {
        require_once 'include/photo/photo_driver.php';
        import_channel_photo(base64url_decode($data['photo']['data']), $data['photo']['type'], get_account_id(), $channel['channel_id']);
    }
    $profiles = $data['profile'];
    if ($profiles) {
        foreach ($profiles as $profile) {
            unset($profile['id']);
            $profile['aid'] = get_account_id();
            $profile['uid'] = $channel['channel_id'];
            // we are going to reset all profile photos to the original
            // somebody will have to fix this later and put all the applicable photos into the export
            $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
            $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
            dbesc_array($profile);
            $r = dbq("INSERT INTO profile (`" . implode("`, `", array_keys($profile)) . "`) VALUES ('" . implode("', '", array_values($profile)) . "')");
        }
    }
    $hublocs = $data['hubloc'];
    if ($hublocs) {
        foreach ($hublocs as $hubloc) {
            $arr = array('guid' => $hubloc['hubloc_guid'], 'guid_sig' => $hubloc['guid_sig'], 'url' => $hubloc['hubloc_url'], 'url_sig' => $hubloc['hubloc_url_sig']);
            if ($hubloc['hubloc_hash'] === $channel['channel_hash'] && $hubloc['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY && $seize) {
                $hubloc['hubloc_flags'] = $hubloc['hubloc_flags'] ^ HUBLOC_FLAGS_PRIMARY;
            }
            if (!zot_gethub($arr)) {
                unset($hubloc['hubloc_id']);
                dbesc_array($hubloc);
                $r = dbq("INSERT INTO hubloc (`" . implode("`, `", array_keys($hubloc)) . "`) VALUES ('" . implode("', '", array_values($hubloc)) . "')");
            }
        }
    }
    // create new hubloc for the new channel at this site
    $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_flags, \n\t\thubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey )\n\t\tvalues ( '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )", dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_hash']), dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), dbesc('zot'), intval($seize ? HUBLOC_FLAGS_PRIMARY : 0), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $channel['channel_prvkey']))), dbesc(get_app()->get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system', 'pubkey')));
    // reset the original primary hubloc if it is being seized
    if ($seize) {
        $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where (hubloc_flags & %d) and hubloc_hash = '%s' and hubloc_url != '%s' ", intval(HUBLOC_FLAGS_PRIMARY), intval(HUBLOC_FLAGS_PRIMARY), dbesc($channel['channel_hash']), dbesc(z_root()));
    }
    // import xchans and contact photos
    if ($seize) {
        // replace our existing xchan if we're seizing control
        $r = q("delete from xchan where xchan_hash = '%s' limit 1", dbesc($channel['channel_hash']));
        $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", dbesc($channel['channel_hash']), dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_pubkey']), dbesc($a->get_baseurl() . "/photo/profile/l/" . $channel['channel_id']), dbesc($a->get_baseurl() . "/photo/profile/m/" . $channel['channel_id']), dbesc($a->get_baseurl() . "/photo/profile/s/" . $channel['channel_id']), dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), dbesc(z_root() . '/channel/' . $channel['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $channel['channel_address']), dbesc($channel['channel_name']), dbesc('zot'), dbesc(datetime_convert()), dbesc(datetime_convert()));
    }
    $xchans = $data['xchan'];
    if ($xchans) {
        foreach ($xchans as $xchan) {
            $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", dbesc($xchan['xchan_hash']));
            if ($r) {
                continue;
            }
            dbesc_array($xchan);
            $r = dbq("INSERT INTO xchan (`" . implode("`, `", array_keys($xchan)) . "`) VALUES ('" . implode("', '", array_values($xchan)) . "')");
            require_once 'include/photo/photo_driver.php';
            $photos = import_profile_photo($xchan['xchan_photo_l'], $xchan['xchan_hash']);
            if ($photos[4]) {
                $photodate = NULL_DATE;
            } else {
                $photodate = $xchan['xchan_photo_date'];
            }
            $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s'\n\t\t\t\twhere xchan_hash = '%s' limit 1", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc($photos[3]), dbesc($photodate), dbesc($xchan_hash));
        }
    }
    // FIXME - ensure we have an xchan if somebody is trying to pull a fast one
    // import contacts
    $abooks = $data['abook'];
    if ($abooks) {
        foreach ($abooks as $abook) {
            unset($abook['abook_id']);
            $abook['abook_account'] = get_account_id();
            $abook['abook_channel'] = $channel['channel_id'];
            dbesc_array($abook);
            $r = dbq("INSERT INTO abook (`" . implode("`, `", array_keys($abook)) . "`) VALUES ('" . implode("', '", array_values($abook)) . "')");
        }
    }
    $configs = $data['config'];
    if ($configs) {
        foreach ($configs as $config) {
            unset($config['id']);
            $config['uid'] = $channel['channel_id'];
            dbesc_array($config);
            $r = dbq("INSERT INTO pconfig (`" . implode("`, `", array_keys($config)) . "`) VALUES ('" . implode("', '", array_values($config)) . "')");
        }
    }
    $groups = $data['group'];
    if ($groups) {
        $saved = array();
        foreach ($groups as $group) {
            $saved[$group['hash']] = array('old' => $group['id']);
            unset($group['id']);
            $group['uid'] = $channel['channel_id'];
            dbesc_array($group);
            $r = dbq("INSERT INTO group (`" . implode("`, `", array_keys($group)) . "`) VALUES ('" . implode("', '", array_values($group)) . "')");
        }
        $r = q("select * from `groups` where uid = %d", intval($channel['channel_id']));
        if ($r) {
            foreach ($r as $rr) {
                $saved[$rr['hash']]['new'] = $rr['id'];
            }
        }
    }
    $group_members = $data['group_member'];
    if ($groups_members) {
        foreach ($group_members as $group_member) {
            unset($group_member['id']);
            $group_member['uid'] = $channel['channel_id'];
            foreach ($saved as $x) {
                if ($x['old'] == $group_member['gid']) {
                    $group_member['gid'] = $x['new'];
                }
            }
            dbesc_array($group_member);
            $r = dbq("INSERT INTO group_member (`" . implode("`, `", array_keys($group_member)) . "`) VALUES ('" . implode("', '", array_values($group_member)) . "')");
        }
    }
    // FIXME - ensure we have a self entry if somebody is trying to pull a fast one
    if ($seize) {
        // notify old server that it is no longer primary.
    }
    // This will indirectly perform a refresh_all *and* update the directory
    proc_run('php', 'include/directory.php', $channel['channel_id']);
    // send out refresh requests
    notice(t('Import completed.') . EOL);
    change_channel($channel['channel_id']);
    goaway(z_root() . '/network');
}
示例#9
0
function store_diaspora_retract_sig($item, $user, $baseurl)
{
    // Note that we can't add a target_author_signature
    // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting
    // the comment, that means we're the home of the post, and Diaspora will only
    // check the parent_author_signature of retractions that it doesn't have to relay further
    //
    // I don't think this function gets called for an "unlike," but I'll check anyway
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('drop_item: diaspora support disabled, not storing retraction signature', LOGGER_DEBUG);
        return;
    }
    logger('drop_item: storing diaspora retraction signature');
    $signed_text = $item['guid'] . ';' . ($item['verb'] === ACTIVITY_LIKE ? 'Like' : 'Comment');
    if (local_user() == $item['uid']) {
        $handle = $user['nickname'] . '@' . substr($baseurl, strpos($baseurl, '://') + 3);
        $authorsig = base64_encode(rsa_sign($signed_text, $user['prvkey'], 'sha256'));
    } else {
        $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", $item['contact-id']);
        if (count($r)) {
            // The below handle only works for NETWORK_DFRN. I think that's ok, because this function
            // only handles DFRN deletes
            $handle_baseurl_start = strpos($r['url'], '://') + 3;
            $handle_baseurl_length = strpos($r['url'], '/profile') - $handle_baseurl_start;
            $handle = $r['nick'] . '@' . substr($r['url'], $handle_baseurl_start, $handle_baseurl_length);
            $authorsig = '';
        }
    }
    if (isset($handle)) {
        q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($item['id']), dbesc($signed_text), dbesc($authorsig), dbesc($handle));
    }
    return;
}
示例#10
0
function zot_reply_auth_check($data, $encrypted_packet)
{
    $ret = array('success' => false);
    /*
     * Requestor visits /magic/?dest=somewhere on their own site with a browser
     * magic redirects them to $destsite/post [with auth args....]
     * $destsite sends an auth_check packet to originator site
     * The auth_check packet is handled here by the originator's site 
     * - the browser session is still waiting
     * inside $destsite/post for everything to verify
     * If everything checks out we'll return a token to $destsite
     * and then $destsite will verify the token, authenticate the browser
     * session and then redirect to the original destination.
     * If authentication fails, the redirection to the original destination
     * will still take place but without authentication.
     */
    logger('mod_zot: auth_check', LOGGER_DEBUG);
    if (!$encrypted_packet) {
        logger('mod_zot: auth_check packet was not encrypted.');
        $ret['message'] .= 'no packet encryption' . EOL;
        json_return_and_die($ret);
    }
    $arr = $data['sender'];
    $sender_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
    // garbage collect any old unused notifications
    // This was and should be 10 minutes but my hosting provider has time lag between the DB and
    // the web server. We should probably convert this to webserver time rather than DB time so
    // that the different clocks won't affect it and allow us to keep the time short.
    q("delete from verify where type = 'auth' and created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('30 MINUTE'));
    $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($sender_hash));
    // We created a unique hash in mod/magic.php when we invoked remote auth, and stored it in
    // the verify table. It is now coming back to us as 'secret' and is signed by a channel at the other end.
    // First verify their signature. We will have obtained a zot-info packet from them as part of the sender
    // verification.
    if (!$y || !rsa_verify($data['secret'], base64url_decode($data['secret_sig']), $y[0]['xchan_pubkey'])) {
        logger('mod_zot: auth_check: sender not found or secret_sig invalid.');
        $ret['message'] .= 'sender not found or sig invalid ' . print_r($y, true) . EOL;
        json_return_and_die($ret);
    }
    // There should be exactly one recipient, the original auth requestor
    $ret['message'] .= 'recipients ' . print_r($recipients, true) . EOL;
    if ($data['recipients']) {
        $arr = $data['recipients'][0];
        $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
        $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1", dbesc($recip_hash));
        if (!$c) {
            logger('mod_zot: auth_check: recipient channel not found.');
            $ret['message'] .= 'recipient not found.' . EOL;
            json_return_and_die($ret);
        }
        $confirm = base64url_encode(rsa_sign($data['secret'] . $recip_hash, $c[0]['channel_prvkey']));
        // This additionally checks for forged sites since we already stored the expected result in meta
        // and we've already verified that this is them via zot_gethub() and that their key signed our token
        $z = q("select id from verify where channel = %d and type = 'auth' and token = '%s' and meta = '%s' limit 1", intval($c[0]['channel_id']), dbesc($data['secret']), dbesc($data['sender']['url']));
        if (!$z) {
            logger('mod_zot: auth_check: verification key not found.');
            $ret['message'] .= 'verification key not found' . EOL;
            json_return_and_die($ret);
        }
        $r = q("delete from verify where id = %d", intval($z[0]['id']));
        $u = q("select account_service_class from account where account_id = %d limit 1", intval($c[0]['channel_account_id']));
        logger('mod_zot: auth_check: success', LOGGER_DEBUG);
        $ret['success'] = true;
        $ret['confirm'] = $confirm;
        if ($u && $u[0]['account_service_class']) {
            $ret['service_class'] = $u[0]['account_service_class'];
        }
        // Set "do not track" flag if this site or this channel's profile is restricted
        // in some way
        if (intval(get_config('system', 'block_public'))) {
            $ret['DNT'] = true;
        }
        if (!perm_is_allowed($c[0]['channel_id'], '', 'view_profile')) {
            $ret['DNT'] = true;
        }
        if (get_pconfig($c[0]['channel_id'], 'system', 'do_not_track')) {
            $ret['DNT'] = true;
        }
        if (get_pconfig($c[0]['channel_id'], 'system', 'hide_online_status')) {
            $ret['DNT'] = true;
        }
        json_return_and_die($ret);
    }
    json_return_and_die($ret);
}
示例#11
0
function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false)
{
    // We won't be able to sign Diaspora comments for authenticated visitors
    // - we don't have their private key
    // since Diaspora doesn't handle edits we can only do this for the original text and not update it.
    require_once 'include/bb2diaspora.php';
    $signed_body = bb2diaspora_itembody($datarray, $walltowall);
    if ($walltowall) {
        logger('wall to wall comment', LOGGER_DEBUG);
        // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
        $signed_body = "\n\n" . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" . $signed_body;
    }
    logger('storing diaspora comment signature', LOGGER_DEBUG);
    $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname();
    $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
    /** @FIXME $uprvkey is undefined, do we still need this if-statement? */
    if ($uprvkey !== false) {
        $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256'));
    } else {
        $authorsig = '';
    }
    $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig));
    $key = get_config('system', 'pubkey');
    $y = crypto_encapsulate(json_encode($x), $key);
    $r = q("update item set diaspora_meta = '%s' where id = %d", dbesc(json_encode($y)), intval($post_id));
    if (!$r) {
        logger('store_diaspora_comment_sig: DB write failed');
    }
    return;
}
示例#12
0
文件: identity.php 项目: 23n/hubzilla
/**
 * @brief Create a new channel.
 *
 * Also creates the related xchan, hubloc, profile, and "self" abook records,
 * and an empty "Friends" group/collection for the new channel.
 *
 * @param array $arr assoziative array with:
 *  * \e string \b name full name of channel
 *  * \e string \b nickname "email/url-compliant" nickname
 *  * \e int \b account_id to attach with this channel
 *  * [other identity fields as desired]
 *
 * @returns array
 *     'success' => boolean true or false
 *     'message' => optional error text if success is false
 *     'channel' => if successful the created channel array
 */
function create_identity($arr)
{
    $a = get_app();
    $ret = array('success' => false);
    if (!$arr['account_id']) {
        $ret['message'] = t('No account identifier');
        return $ret;
    }
    $ret = identity_check_service_class($arr['account_id']);
    if (!$ret['success']) {
        return $ret;
    }
    // save this for auto_friending
    $total_identities = $ret['total_identities'];
    $nick = mb_strtolower(trim($arr['nickname']));
    if (!$nick) {
        $ret['message'] = t('Nickname is required.');
        return $ret;
    }
    $name = escape_tags($arr['name']);
    $pageflags = x($arr, 'pageflags') ? intval($arr['pageflags']) : PAGE_NORMAL;
    $system = x($arr, 'system') ? intval($arr['system']) : 0;
    $name_error = validate_channelname($arr['name']);
    if ($name_error) {
        $ret['message'] = $name_error;
        return $ret;
    }
    if ($nick === 'sys' && !$system) {
        $ret['message'] = t('Reserved nickname. Please choose another.');
        return $ret;
    }
    if (check_webbie(array($nick)) !== $nick) {
        $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
        return $ret;
    }
    $guid = zot_new_uid($nick);
    $key = new_keypair(4096);
    $sig = base64url_encode(rsa_sign($guid, $key['prvkey']));
    $hash = make_xchan_hash($guid, $sig);
    // Force a few things on the short term until we can provide a theme or app with choice
    $publish = 1;
    if (array_key_exists('publish', $arr)) {
        $publish = intval($arr['publish']);
    }
    $primary = true;
    if (array_key_exists('primary', $arr)) {
        $primary = intval($arr['primary']);
    }
    $role_permissions = null;
    $global_perms = get_perms();
    if (array_key_exists('permissions_role', $arr) && $arr['permissions_role']) {
        $role_permissions = get_role_perms($arr['permissions_role']);
        if ($role_permissions) {
            foreach ($role_permissions as $p => $v) {
                if (strpos($p, 'channel_') !== false) {
                    $perms_keys .= ', ' . $p;
                    $perms_vals .= ', ' . intval($v);
                }
                if ($p === 'directory_publish') {
                    $publish = intval($v);
                }
            }
        }
    } else {
        $defperms = site_default_perms();
        foreach ($defperms as $p => $v) {
            $perms_keys .= ', ' . $global_perms[$p][0];
            $perms_vals .= ', ' . intval($v);
        }
    }
    $expire = 0;
    $r = q("insert into channel ( channel_account_id, channel_primary, \n\t\tchannel_name, channel_address, channel_guid, channel_guid_sig,\n\t\tchannel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_system, channel_expire_days, channel_timezone {$perms_keys} )\n\t\tvalues ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s' {$perms_vals} ) ", intval($arr['account_id']), intval($primary), dbesc($name), dbesc($nick), dbesc($guid), dbesc($sig), dbesc($hash), dbesc($key['prvkey']), dbesc($key['pubkey']), intval($pageflags), intval($system), intval($expire), dbesc($a->timezone));
    $r = q("select * from channel where channel_account_id = %d \n\t\tand channel_guid = '%s' limit 1", intval($arr['account_id']), dbesc($guid));
    if (!$r) {
        $ret['message'] = t('Unable to retrieve created identity');
        return $ret;
    }
    $ret['channel'] = $r[0];
    if (intval($arr['account_id'])) {
        set_default_login_identity($arr['account_id'], $ret['channel']['channel_id'], false);
    }
    // Create a verified hub location pointing to this site.
    $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary, \n\t\thubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network )\n\t\tvalues ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($guid), dbesc($sig), dbesc($hash), dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $ret['channel']['channel_prvkey']))), dbesc(get_app()->get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system', 'pubkey')), dbesc('zot'));
    if (!$r) {
        logger('create_identity: Unable to store hub location');
    }
    $newuid = $ret['channel']['channel_id'];
    $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_system ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", dbesc($hash), dbesc($guid), dbesc($sig), dbesc($key['pubkey']), dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/s/{$newuid}"), dbesc($ret['channel']['channel_address'] . '@' . get_app()->get_hostname()), dbesc(z_root() . '/channel/' . $ret['channel']['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $ret['channel']['channel_address']), dbesc($ret['channel']['channel_name']), dbesc('zot'), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($system));
    // Not checking return value.
    // It's ok for this to fail if it's an imported channel, and therefore the hash is a duplicate
    $r = q("INSERT INTO profile ( aid, uid, profile_guid, profile_name, is_default, publish, name, photo, thumb)\n\t\tVALUES ( %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s') ", intval($ret['channel']['channel_account_id']), intval($newuid), dbesc(random_string()), t('Default Profile'), 1, $publish, dbesc($ret['channel']['channel_name']), dbesc($a->get_baseurl() . "/photo/profile/l/{$newuid}"), dbesc($a->get_baseurl() . "/photo/profile/m/{$newuid}"));
    if ($role_permissions) {
        $myperms = array_key_exists('perms_auto', $role_permissions) && $role_permissions['perms_auto'] ? intval($role_permissions['perms_accept']) : 0;
    } else {
        $myperms = PERMS_R_STREAM | PERMS_R_PROFILE | PERMS_R_PHOTOS | PERMS_R_ABOOK | PERMS_W_STREAM | PERMS_W_WALL | PERMS_W_COMMENT | PERMS_W_MAIL | PERMS_W_CHAT | PERMS_R_STORAGE | PERMS_R_PAGES | PERMS_W_LIKE;
    }
    $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_self, abook_my_perms )\n\t\tvalues ( %d, %d, '%s', %d, '%s', '%s', %d, %d ) ", intval($ret['channel']['channel_account_id']), intval($newuid), dbesc($hash), intval(0), dbesc(datetime_convert()), dbesc(datetime_convert()), intval(1), intval($myperms));
    if (intval($ret['channel']['channel_account_id'])) {
        // Save our permissions role so we can perhaps call it up and modify it later.
        if ($role_permissions) {
            set_pconfig($newuid, 'system', 'permissions_role', $arr['permissions_role']);
            if (array_key_exists('online', $role_permissions)) {
                set_pconfig($newuid, 'system', 'hide_presence', 1 - intval($role_permissions['online']));
            }
            if (array_key_exists('perms_auto', $role_permissions)) {
                set_pconfig($newuid, 'system', 'autoperms', $role_permissions['perms_auto'] ? $role_permissions['perms_accept'] : 0);
            }
        }
        // Create a group with yourself as a member. This allows somebody to use it
        // right away as a default group for new contacts.
        require_once 'include/group.php';
        group_add($newuid, t('Friends'));
        group_add_member($newuid, t('Friends'), $ret['channel']['channel_hash']);
        // if our role_permissions indicate that we're using a default collection ACL, add it.
        if (is_array($role_permissions) && $role_permissions['default_collection']) {
            $r = q("select hash from groups where uid = %d and name = '%s' limit 1", intval($newuid), dbesc(t('Friends')));
            if ($r) {
                q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d", dbesc($r[0]['hash']), dbesc('<' . $r[0]['hash'] . '>'), intval($newuid));
            }
        }
        if (!$system) {
            set_pconfig($ret['channel']['channel_id'], 'system', 'photo_path', '%Y-%m');
            set_pconfig($ret['channel']['channel_id'], 'system', 'attach_path', '%Y-%m');
        }
        // auto-follow any of the hub's pre-configured channel choices.
        // Only do this if it's the first channel for this account;
        // otherwise it could get annoying. Don't make this list too big
        // or it will impact registration time.
        $accts = get_config('system', 'auto_follow');
        if ($accts && !$total_identities) {
            require_once 'include/follow.php';
            if (!is_array($accts)) {
                $accts = array($accts);
            }
            foreach ($accts as $acct) {
                if (trim($acct)) {
                    new_contact($newuid, trim($acct), $ret['channel'], false);
                }
            }
        }
        call_hooks('create_identity', $newuid);
        proc_run('php', 'include/directory.php', $ret['channel']['channel_id']);
    }
    $ret['success'] = true;
    return $ret;
}
示例#13
0
function diaspora_send_mail($item, $owner, $contact)
{
    $a = get_app();
    $myaddr = $owner['channel_address'] . '@' . App::get_hostname();
    $r = q("select * from conv where guid = '%s' and uid = %d limit 1", dbesc($item['conv_guid']), intval($item['channel_id']));
    if (!count($r)) {
        logger('diaspora_send_mail: conversation not found.');
        return;
    }
    $z = q("select from_xchan from mail where conv_guid = '%s' and channel_id = %d and mid = parent_mid limit 1", dbesc($item['conv_guid']), intval($item['channel_id']));
    $conv_owner = $z && $z[0]['from_xchan'] === $owner['channel_hash'] ? true : false;
    $cnv = $r[0];
    $cnv['subject'] = base64url_decode(str_rot47($cnv['subject']));
    $conv = array('guid' => xmlify($cnv['guid']), 'subject' => xmlify($cnv['subject']), 'created_at' => xmlify(datetime_convert('UTC', 'UTC', $cnv['created'], 'Y-m-d H:i:s \\U\\T\\C')), 'diaspora_handle' => xmlify($cnv['creator']), 'participant_handles' => xmlify($cnv['recips']));
    if (array_key_exists('mail_obscured', $item) && intval($item['mail_obscured'])) {
        if ($item['title']) {
            $item['title'] = base64url_decode(str_rot47($item['title']));
        }
        if ($item['body']) {
            $item['body'] = base64url_decode(str_rot47($item['body']));
        }
    }
    // the parent_guid needs to be the conversation guid
    $parent_ptr = $cnv['guid'];
    $body = bb2diaspora($item['body']);
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    $signed_text = $item['mid'] . ';' . $parent_ptr . ';' . $body . ';' . $created . ';' . $myaddr . ';' . $cnv['guid'];
    $sig = base64_encode(rsa_sign($signed_text, $owner['channel_prvkey'], 'sha256'));
    $msg = array('guid' => xmlify($item['mid']), 'parent_guid' => xmlify($parent_ptr), 'parent_author_signature' => $conv_owner ? xmlify($sig) : null, 'author_signature' => xmlify($sig), 'text' => xmlify($body), 'created_at' => xmlify($created), 'diaspora_handle' => xmlify($myaddr), 'conversation_guid' => xmlify($cnv['guid']));
    if ($item['mail_isreply']) {
        $tpl = get_markup_template('diaspora_message.tpl', 'addon/diaspora');
        $xmsg = replace_macros($tpl, array('$msg' => $msg));
    } else {
        $conv['messages'] = array($msg);
        $tpl = get_markup_template('diaspora_conversation.tpl', 'addon/diaspora');
        $xmsg = replace_macros($tpl, array('$conv' => $conv));
    }
    logger('diaspora_conversation: ' . print_r($xmsg, true), LOGGER_DATA);
    $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg, $owner, $contact, $owner['channel_prvkey'], $contact['xchan_pubkey'], false)));
    return diaspora_queue($owner, $contact, $slap, false, $item['mid']);
}
示例#14
0
function item_url_replace($channel, &$item, $old, $new, $oldnick = '')
{
    if ($item['attach']) {
        json_url_replace($old, $new, $item['attach']);
        if ($oldnick) {
            json_url_replace('/' . $oldnick . '/', '/' . $channel['channel_address'] . '/', $item['attach']);
        }
    }
    if ($item['object']) {
        json_url_replace($old, $new, $item['object']);
        if ($oldnick) {
            json_url_replace('/' . $oldnick . '/', '/' . $channel['channel_address'] . '/', $item['object']);
        }
    }
    if ($item['target']) {
        json_url_replace($old, $new, $item['target']);
        if ($oldnick) {
            json_url_replace('/' . $oldnick . '/', '/' . $channel['channel_address'] . '/', $item['target']);
        }
    }
    if (string_replace($old, $new, $item['body'])) {
        $item['sig'] = base64url_encode(rsa_sign($item['body'], $channel['channel_prvkey']));
        $item['item_verified'] = 1;
    }
    $item['plink'] = str_replace($old, $new, $item['plink']);
    if ($oldnick) {
        $item['plink'] = str_replace('/' . $oldnick . '/', '/' . $channel['channel_address'] . '/', $item['plink']);
    }
    $item['llink'] = str_replace($old, $new, $item['llink']);
    if ($oldnick) {
        $item['llink'] = str_replace('/' . $oldnick . '/', '/' . $channel['channel_address'] . '/', $item['llink']);
    }
}
示例#15
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'];
    // 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;
}
示例#16
0
function diaspora_magic_env($channel, $msg)
{
    $data = preg_replace('/s+/', '', base64url_encode($msg));
    $keyhash = base64url_encode(channel_reddress($channel));
    $type = 'application/xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign($data . $precomputed, $channel['channel_prvkey']));
    return replace_macros(get_markup_template('magicsig.tpl', 'addon/diaspora'), ['$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature]);
}
示例#17
0
function slapper($owner, $url, $slap)
{
    logger('slapper called for ' . $url . '. Data: ' . $slap);
    // does contact have a salmon endpoint?
    if (!strlen($url)) {
        return;
    }
    if (!$owner['sprvkey']) {
        logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.", $owner['username'], $owner['uid']));
        return;
    }
    // add all namespaces to item
    $namespaces = <<<EOT
<entry xmlns="http://www.w3.org/2005/Atom"
      xmlns:thr="http://purl.org/syndication/thread/1.0"
      xmlns:at="http://purl.org/atompub/tombstones/1.0"
      xmlns:media="http://purl.org/syndication/atommedia"
      xmlns:dfrn="http://purl.org/macgirvin/dfrn/1.0" 
      xmlns:as="http://activitystrea.ms/spec/1.0/"
      xmlns:georss="http://www.georss.org/georss" 
      xmlns:poco="http://portablecontacts.net/spec/1.0" 
      xmlns:ostatus="http://ostatus.org/schema/1.0" 
\t  xmlns:statusnet="http://status.net/schema/api/1/" >\t\t\t\t\t\t\t\t\t\t\t\t\t>
EOT;
    $slap = str_replace('<entry>', $namespaces, $slap);
    // create a magic envelope
    $data = base64url_encode($slap);
    $data_type = 'application/atom+xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
    // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
    $signature2 = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
    $signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey']));
    $salmon_tpl = get_markup_template('magicsig.tpl');
    $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature));
    // slap them
    post_url($url, $salmon, array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon)));
    $a = get_app();
    $return_code = $a->get_curl_code();
    // check for success, e.g. 2xx
    if ($return_code > 299) {
        logger('compliant salmon failed. Falling back to status.net hack2');
        // Entirely likely that their salmon implementation is
        // non-compliant. Let's try once more, this time only signing
        // the data, without stripping '=' chars
        $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature2));
        // slap them
        post_url($url, $salmon, array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon)));
        $return_code = $a->get_curl_code();
        if ($return_code > 299) {
            logger('compliant salmon failed. Falling back to status.net hack3');
            // Entirely likely that their salmon implementation is
            // non-compliant. Let's try once more, this time only signing
            // the data, without the precomputed blob
            $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature3));
            // slap them
            post_url($url, $salmon, array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon)));
            $return_code = $a->get_curl_code();
        }
    }
    logger('slapper for ' . $url . ' returned ' . $return_code);
    if (!$return_code) {
        return -1;
    }
    if ($return_code == 503 && stristr($a->get_curl_headers(), 'retry-after')) {
        return -1;
    }
    return $return_code >= 200 && $return_code < 300 ? 0 : 1;
}
示例#18
0
function sync_files($channel, $files)
{
    require_once 'include/attach.php';
    if ($channel && $files) {
        foreach ($files as $f) {
            if (!$f) {
                continue;
            }
            $fetch_url = $f['fetch_url'];
            $oldbase = dirname($fetch_url);
            $original_channel = $f['original_channel'];
            if (!($fetch_url && $original_channel)) {
                continue;
            }
            if ($f['attach']) {
                $attachment_stored = false;
                foreach ($f['attach'] as $att) {
                    convert_oldfields($att, 'data', 'content');
                    if ($att['deleted']) {
                        attach_delete($channel, $att['hash']);
                        continue;
                    }
                    $attach_exists = false;
                    $x = attach_by_hash($att['hash']);
                    logger('sync_files duplicate check: attach_exists=' . $attach_exists, LOGGER_DEBUG);
                    logger('sync_files duplicate check: att=' . print_r($att, true), LOGGER_DEBUG);
                    logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x, true), LOGGER_DEBUG);
                    if ($x['success']) {
                        $attach_exists = true;
                        $attach_id = $x[0]['id'];
                    }
                    $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
                    unset($att['id']);
                    $att['aid'] = $channel['channel_account_id'];
                    $att['uid'] = $channel['channel_id'];
                    // check for duplicate folder names with the same parent.
                    // If we have a duplicate that doesn't match this hash value
                    // change the name so that the contents won't be "covered over"
                    // by the existing directory. Use the same logic we use for
                    // duplicate files.
                    if (strpos($att['filename'], '.') !== false) {
                        $basename = substr($att['filename'], 0, strrpos($att['filename'], '.'));
                        $ext = substr($att['filename'], strrpos($att['filename'], '.'));
                    } else {
                        $basename = $att['filename'];
                        $ext = '';
                    }
                    $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' and hash != '%s' ", dbesc($basename . $ext), dbesc($basename . '(%)' . $ext), dbesc($att['folder']), dbesc($att['hash']));
                    if ($r) {
                        $x = 1;
                        do {
                            $found = false;
                            foreach ($r as $rr) {
                                if ($rr['filename'] === $basename . '(' . $x . ')' . $ext) {
                                    $found = true;
                                    break;
                                }
                            }
                            if ($found) {
                                $x++;
                            }
                        } while ($found);
                        $att['filename'] = $basename . '(' . $x . ')' . $ext;
                    } else {
                        $att['filename'] = $basename . $ext;
                    }
                    // end duplicate detection
                    // @fixme - update attachment structures if they are modified rather than created
                    $att['content'] = $newfname;
                    // Note: we use $att['hash'] below after it has been escaped to
                    // fetch the file contents.
                    // If the hash ever contains any escapable chars this could cause
                    // problems. Currently it does not.
                    dbesc_array($att);
                    if ($attach_exists) {
                        logger('sync_files attach exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $str = '';
                        foreach ($att as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id));
                    } else {
                        logger('sync_files attach does not exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $r = dbq("INSERT INTO attach (`" . implode("`, `", array_keys($att)) . "`) VALUES ('" . implode("', '", array_values($att)) . "')");
                    }
                    // is this a directory?
                    if ($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
                        os_mkdir($newfname, STORAGE_DEFAULT_PERMISSIONS, true);
                        $attachment_stored = true;
                        continue;
                    } else {
                        // it's a file
                        // for the sync version of this algorithm (as opposed to 'offline import')
                        // we will fetch the actual file from the source server so it can be
                        // streamed directly to disk and avoid consuming PHP memory if it's a huge
                        // audio/video file or something.
                        $time = datetime_convert();
                        $parr = array('hash' => $channel['channel_hash'], 'time' => $time, 'resource' => $att['hash'], 'revision' => 0, 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])));
                        $store_path = $newfname;
                        $fp = fopen($newfname, 'w');
                        if (!$fp) {
                            logger('failed to open storage file.', LOGGER_NORMAL, LOG_ERR);
                            continue;
                        }
                        $redirects = 0;
                        $x = z_post_url($fetch_url, $parr, $redirects, array('filep' => $fp));
                        fclose($fp);
                        if ($x['success']) {
                            $attachment_stored = true;
                        }
                        continue;
                    }
                }
            }
            if (!$attachment_stored) {
                // @TODO should we queue this and retry or delete everything or what?
                logger('attachment store failed', LOGGER_NORMAL, LOG_ERR);
            }
            if ($f['photo']) {
                foreach ($f['photo'] as $p) {
                    unset($p['id']);
                    $p['aid'] = $channel['channel_account_id'];
                    $p['uid'] = $channel['channel_id'];
                    convert_oldfields($p, 'data', 'content');
                    convert_oldfields($p, 'scale', 'imgscale');
                    convert_oldfields($p, 'size', 'filesize');
                    convert_oldfields($p, 'type', 'mimetype');
                    // if this is a profile photo, undo the profile photo bit
                    // for any other photo which previously held it.
                    if ($p['photo_usage'] == PHOTO_PROFILE) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    // same for cover photos
                    if ($p['photo_usage'] == PHOTO_COVER) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_COVER), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    if ($p['imgscale'] === 0 && $p['os_storage']) {
                        $p['content'] = $store_path;
                    } else {
                        $p['content'] = base64_decode($p['content']);
                    }
                    $exists = q("select * from photo where resource_id = '%s' and imgscale = %d and uid = %d limit 1", dbesc($p['resource_id']), intval($p['imgscale']), intval($channel['channel_id']));
                    dbesc_array($p);
                    if ($exists) {
                        $str = '';
                        foreach ($p as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `photo` set " . $str . " where id = " . intval($exists[0]['id']));
                    } else {
                        $r = dbq("INSERT INTO photo (`" . implode("`, `", array_keys($p)) . "`) VALUES ('" . implode("', '", array_values($p)) . "')");
                    }
                }
            }
            if ($f['item']) {
                sync_items($channel, $f['item'], ['channel_address' => $original_channel, 'url' => $oldbase]);
            }
        }
    }
}
示例#19
0
 function init()
 {
     $ret = array('success' => false, 'url' => '', 'message' => '');
     logger('mod_magic: invoked', LOGGER_DEBUG);
     logger('mod_magic: args: ' . print_r($_REQUEST, true), LOGGER_DATA);
     $addr = x($_REQUEST, 'addr') ? $_REQUEST['addr'] : '';
     $dest = x($_REQUEST, 'dest') ? $_REQUEST['dest'] : '';
     $test = x($_REQUEST, 'test') ? intval($_REQUEST['test']) : 0;
     $rev = x($_REQUEST, 'rev') ? intval($_REQUEST['rev']) : 0;
     $delegate = x($_REQUEST, 'delegate') ? $_REQUEST['delegate'] : '';
     $parsed = parse_url($dest);
     if (!$parsed) {
         if ($test) {
             $ret['message'] .= 'could not parse ' . $dest . EOL;
             return $ret;
         }
         goaway($dest);
     }
     $basepath = $parsed['scheme'] . '://' . $parsed['host'] . ($parsed['port'] ? ':' . $parsed['port'] : '');
     $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", dbesc($basepath));
     if (!$x) {
         /*
          * We have no records for, or prior communications with this hub. 
          * If an address was supplied, let's finger them to create a hub record. 
          * Otherwise we'll use the special address '[system]' which will return
          * either a system channel or the first available normal channel. We don't
          * really care about what channel is returned - we need the hub information 
          * from that response so that we can create signed auth packets destined 
          * for that hub.
          *
          */
         $ret = zot_finger($addr ? $addr : '[system]@' . $parsed['host'], null);
         if ($ret['success']) {
             $j = json_decode($ret['body'], true);
             if ($j) {
                 import_xchan($j);
             }
             // Now try again
             $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", dbesc($basepath));
         }
     }
     if (!$x) {
         if ($rev) {
             goaway($dest);
         } else {
             logger('mod_magic: no channels found for requested hub.' . print_r($_REQUEST, true));
             if ($test) {
                 $ret['message'] .= 'This site has no previous connections with ' . $basepath . EOL;
                 return $ret;
             }
             notice(t('Hub not found.') . EOL);
             return;
         }
     }
     // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating.
     // By default, we'll proceed without asking.
     $arr = array('channel_id' => local_channel(), 'xchan' => $x[0], 'destination' => $dest, 'proceed' => true);
     call_hooks('magic_auth', $arr);
     $dest = $arr['destination'];
     if (!$arr['proceed']) {
         if ($test) {
             $ret['message'] .= 'cancelled by plugin.' . EOL;
             return $ret;
         }
         goaway($dest);
     }
     if (get_observer_hash() && $x[0]['hubloc_url'] === z_root()) {
         // We are already authenticated on this site and a registered observer.
         // Just redirect.
         if ($test) {
             $ret['success'] = true;
             $ret['message'] .= 'Local site - you are already authenticated.' . EOL;
             return $ret;
         }
         $delegation_success = false;
         if ($delegate) {
             $r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1", dbesc($delegate));
             if ($r && intval($r[0]['channel_id'])) {
                 $allowed = perm_is_allowed($r[0]['channel_id'], get_observer_hash(), 'delegate');
                 if ($allowed) {
                     $_SESSION['delegate_channel'] = $r[0]['channel_id'];
                     $_SESSION['delegate'] = get_observer_hash();
                     $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
                     change_channel($r[0]['channel_id']);
                     $delegation_success = true;
                 }
             }
         }
         // FIXME: check and honour local delegation
         goaway($dest);
     }
     if (local_channel()) {
         $channel = \App::get_channel();
         $token = random_string();
         $token_sig = base64url_encode(rsa_sign($token, $channel['channel_prvkey']));
         $channel['token'] = $token;
         $channel['token_sig'] = $token_sig;
         \Zotlabs\Zot\Verify::create('auth', $channel['channel_id'], $token, $x[0]['hubloc_url']);
         $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode($channel['channel_address'] . '@' . \App::get_hostname()) . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION;
         if ($delegate) {
             $target_url .= '&delegate=' . urlencode($delegate);
         }
         logger('mod_magic: redirecting to: ' . $target_url, LOGGER_DEBUG);
         if ($test) {
             $ret['success'] = true;
             $ret['url'] = $target_url;
             $ret['message'] = 'token ' . $token . ' created for channel ' . $channel['channel_id'] . ' for url ' . $x[0]['hubloc_url'] . EOL;
             return $ret;
         }
         goaway($target_url);
     }
     if ($test) {
         $ret['message'] = 'Not authenticated or invalid arguments to mod_magic' . EOL;
         return $ret;
     }
     goaway($dest);
 }
示例#20
0
文件: like.php 项目: vinzv/friendica
function store_diaspora_like_sig($activity, $post_type, $contact, $post_id)
{
    // Note that we can only create a signature for a user of the local server. We don't have
    // a key for remote users. That is ok, because if a remote user is "unlike"ing a post, it
    // means we are the relay, and for relayable_retractions, Diaspora
    // only checks the parent_author_signature if it doesn't have to relay further
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('mod_like: diaspora support disabled, not storing like signature', LOGGER_DEBUG);
        return;
    }
    logger('mod_like: storing diaspora like signature');
    if ($activity === ACTIVITY_LIKE && $post_type === t('status')) {
        // Only works for NETWORK_DFRN
        $contact_baseurl_start = strpos($contact['url'], '://') + 3;
        $contact_baseurl_length = strpos($contact['url'], '/profile') - $contact_baseurl_start;
        $contact_baseurl = substr($contact['url'], $contact_baseurl_start, $contact_baseurl_length);
        $diaspora_handle = $contact['nick'] . '@' . $contact_baseurl;
        // Get contact's private key if he's a user of the local Friendica server
        $r = q("SELECT `contact`.`uid` FROM `contact` WHERE `url` = '%s' AND `self` = 1 LIMIT 1", dbesc($contact['url']));
        if ($r) {
            $contact_uid = $r['uid'];
            $r = q("SELECT prvkey FROM user WHERE uid = %d LIMIT 1", intval($contact_uid));
            if ($r) {
                $contact_uprvkey = $r['prvkey'];
            }
        }
        $r = q("SELECT guid, parent FROM `item` WHERE id = %d LIMIT 1", intval($post_id));
        if ($r) {
            $p = q("SELECT guid FROM `item` WHERE id = %d AND parent = %d LIMIT 1", intval($r[0]['parent']), intval($r[0]['parent']));
            if ($p) {
                $signed_text = $r[0]['guid'] . ';Post;' . $p[0]['guid'] . ';true;' . $diaspora_handle;
                if (isset($contact_uprvkey)) {
                    $authorsig = base64_encode(rsa_sign($signed_text, $contact_uprvkey, 'sha256'));
                } else {
                    $authorsig = '';
                }
                q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), dbesc($signed_text), dbesc($authorsig), dbesc($diaspora_handle));
            }
        }
    }
    return;
}
示例#21
0
function zfinger_init(&$a)
{
    require_once 'include/zot.php';
    require_once 'include/crypto.php';
    $ret = array('success' => false);
    $zhash = x($_REQUEST, 'guid_hash') ? $_REQUEST['guid_hash'] : '';
    $zguid = x($_REQUEST, 'guid') ? $_REQUEST['guid'] : '';
    $zguid_sig = x($_REQUEST, 'guid_sig') ? $_REQUEST['guid_sig'] : '';
    $zaddr = x($_REQUEST, 'address') ? $_REQUEST['address'] : '';
    $ztarget = x($_REQUEST, 'target') ? $_REQUEST['target'] : '';
    $zsig = x($_REQUEST, 'target_sig') ? $_REQUEST['target_sig'] : '';
    $zkey = x($_REQUEST, 'key') ? $_REQUEST['key'] : '';
    $mindate = x($_REQUEST, 'mindate') ? $_REQUEST['mindate'] : '';
    $feed = x($_REQUEST, 'feed') ? intval($_REQUEST['feed']) : 0;
    if ($ztarget) {
        if (!$zkey || !$zsig || !rsa_verify($ztarget, base64url_decode($zsig), $zkey)) {
            logger('zfinger: invalid target signature');
            $ret['message'] = t("invalid target signature");
            json_return_and_die($ret);
        }
    }
    // allow re-written domains so bob@foo.example.com can provide an address of bob@example.com
    // The top-level domain also needs to redirect .well-known/zot-info to the sub-domain with a 301 or 308
    // TODO: Make 308 work in include/network.php for zot_fetch_url and zot_post_url
    if ($zaddr && ($s = get_config('system', 'zotinfo_domainrewrite'))) {
        $arr = explode('^', $s);
        if (count($arr) == 2) {
            $zaddr = str_replace($arr[0], $arr[1], $zaddr);
        }
    }
    $r = null;
    if (strlen($zhash)) {
        $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash \n\t\t\twhere channel_hash = '%s' limit 1", dbesc($zhash));
    } elseif (strlen($zguid) && strlen($zguid_sig)) {
        $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash \n\t\t\twhere channel_guid = '%s' and channel_guid_sig = '%s' limit 1", dbesc($zguid), dbesc($zguid_sig));
    } elseif (strlen($zaddr)) {
        if (strpos($zaddr, '[system]') === false) {
            /* normal address lookup */
            $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash\n\t\t\t\twhere ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", dbesc($zaddr), dbesc($zaddr));
        } else {
            /**
             * The special address '[system]' will return a system channel if one has been defined,
             * Or the first valid channel we find if there are no system channels. 
             *
             * This is used by magic-auth if we have no prior communications with this site - and
             * returns an identity on this site which we can use to create a valid hub record so that
             * we can exchange signed messages. The precise identity is irrelevant. It's the hub
             * information that we really need at the other end - and this will return it.
             *
             */
            $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash\n\t\t\t\twhere ( channel_pageflags & %d )>0 order by channel_id limit 1", intval(PAGE_SYSTEM));
            if (!$r) {
                $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash\n\t\t\t\t\twhere not ( channel_pageflags & %d )>0 order by channel_id limit 1", intval(PAGE_REMOVED));
            }
        }
    } else {
        $ret['message'] = 'Invalid request';
        json_return_and_die($ret);
    }
    if (!$r) {
        $ret['message'] = 'Item not found.';
        json_return_and_die($ret);
    }
    $e = $r[0];
    $id = $e['channel_id'];
    $sys_channel = $e['channel_pageflags'] & PAGE_SYSTEM ? true : false;
    $special_channel = $e['channel_pageflags'] & PAGE_PREMIUM ? true : false;
    $adult_channel = $e['channel_pageflags'] & PAGE_ADULT ? true : false;
    $censored = $e['channel_pageflags'] & PAGE_CENSORED ? true : false;
    $searchable = $e['channel_pageflags'] & PAGE_HIDDEN ? false : true;
    $deleted = $e['xchan_flags'] & XCHAN_FLAGS_DELETED ? true : false;
    if ($deleted || $censored || $sys_channel) {
        $searchable = false;
    }
    $public_forum = false;
    $role = get_pconfig($e['channel_id'], 'system', 'permissions_role');
    if ($role === 'forum') {
        $public_forum = true;
    } else {
        // check if it has characteristics of a public forum based on custom permissions.
        $t = q("select abook_my_perms from abook where abook_channel = %d and (abook_flags & %d)>0 limit 1", intval($e['channel_id']), intval(ABOOK_FLAG_SELF));
        if ($t && $t[0]['abook_my_perms'] & PERMS_W_TAGWALL) {
            $public_forum = true;
        }
    }
    //  This is for birthdays and keywords, but must check access permissions
    $p = q("select * from profile where uid = %d and is_default = 1", intval($e['channel_id']));
    $profile = array();
    if ($p) {
        if (!intval($p[0]['publish'])) {
            $searchable = false;
        }
        $profile['description'] = $p[0]['pdesc'];
        $profile['birthday'] = $p[0]['dob'];
        if ($profile['birthday'] != '0000-00-00' && ($bd = z_birthday($p[0]['dob'], $e['channel_timezone'])) !== '') {
            $profile['next_birthday'] = $bd;
        }
        if ($age = age($p[0]['dob'], $e['channel_timezone'], '')) {
            $profile['age'] = $age;
        }
        $profile['gender'] = $p[0]['gender'];
        $profile['marital'] = $p[0]['marital'];
        $profile['sexual'] = $p[0]['sexual'];
        $profile['locale'] = $p[0]['locality'];
        $profile['region'] = $p[0]['region'];
        $profile['postcode'] = $p[0]['postal_code'];
        $profile['country'] = $p[0]['country_name'];
        $profile['about'] = $p[0]['about'];
        $profile['homepage'] = $p[0]['homepage'];
        $profile['hometown'] = $p[0]['hometown'];
        if ($p[0]['keywords']) {
            $tags = array();
            $k = explode(' ', $p[0]['keywords']);
            if ($k) {
                foreach ($k as $kk) {
                    if (trim($kk, " \t\n\r\v,")) {
                        $tags[] = trim($kk, " \t\n\r\v,");
                    }
                }
            }
            if ($tags) {
                $profile['keywords'] = $tags;
            }
        }
    }
    $ret['success'] = true;
    // Communication details
    $ret['guid'] = $e['xchan_guid'];
    $ret['guid_sig'] = $e['xchan_guid_sig'];
    $ret['key'] = $e['xchan_pubkey'];
    $ret['name'] = $e['xchan_name'];
    $ret['name_updated'] = $e['xchan_name_date'];
    $ret['address'] = $e['xchan_addr'];
    $ret['photo_mimetype'] = $e['xchan_photo_mimetype'];
    $ret['photo'] = $e['xchan_photo_l'];
    $ret['photo_updated'] = $e['xchan_photo_date'];
    $ret['url'] = $e['xchan_url'];
    $ret['connections_url'] = $e['xchan_connurl'] ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address'];
    $ret['target'] = $ztarget;
    $ret['target_sig'] = $zsig;
    $ret['searchable'] = $searchable;
    $ret['adult_content'] = $adult_channel;
    $ret['public_forum'] = $public_forum;
    if ($deleted) {
        $ret['deleted'] = $deleted;
    }
    // premium or other channel desiring some contact with potential followers before connecting.
    // This is a template - %s will be replaced with the follow_url we discover for the return channel.
    if ($special_channel) {
        $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address'];
    }
    // This is a template for our follow url, %s will be replaced with a webbie
    $ret['follow_url'] = z_root() . '/follow?f=&url=%s';
    $ztarget_hash = $ztarget && $zsig ? make_xchan_hash($ztarget, $zsig) : '';
    $permissions = get_all_perms($e['channel_id'], $ztarget_hash, false);
    if ($ztarget_hash) {
        $permissions['connected'] = false;
        $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($ztarget_hash), intval($e['channel_id']));
        if ($b) {
            $permissions['connected'] = true;
        }
    }
    $ret['permissions'] = $ztarget && $zkey ? crypto_encapsulate(json_encode($permissions), $zkey) : $permissions;
    if ($permissions['view_profile']) {
        $ret['profile'] = $profile;
    }
    // array of (verified) hubs this channel uses
    $x = zot_encode_locations($e);
    if ($x) {
        $ret['locations'] = $x;
    }
    $ret['site'] = array();
    $ret['site']['url'] = z_root();
    $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(), $e['channel_prvkey']));
    $dirmode = get_config('system', 'directory_mode');
    if ($dirmode === false || $dirmode == DIRECTORY_MODE_NORMAL) {
        $ret['site']['directory_mode'] = 'normal';
    }
    if ($dirmode == DIRECTORY_MODE_PRIMARY) {
        $ret['site']['directory_mode'] = 'primary';
    } elseif ($dirmode == DIRECTORY_MODE_SECONDARY) {
        $ret['site']['directory_mode'] = 'secondary';
    } elseif ($dirmode == DIRECTORY_MODE_STANDALONE) {
        $ret['site']['directory_mode'] = 'standalone';
    }
    if ($dirmode != DIRECTORY_MODE_NORMAL) {
        $ret['site']['directory_url'] = z_root() . '/dirsearch';
    }
    // hide detailed site information if you're off the grid
    if ($dirmode != DIRECTORY_MODE_STANDALONE) {
        $register_policy = intval(get_config('system', 'register_policy'));
        if ($register_policy == REGISTER_CLOSED) {
            $ret['site']['register_policy'] = 'closed';
        }
        if ($register_policy == REGISTER_APPROVE) {
            $ret['site']['register_policy'] = 'approve';
        }
        if ($register_policy == REGISTER_OPEN) {
            $ret['site']['register_policy'] = 'open';
        }
        $access_policy = intval(get_config('system', 'access_policy'));
        if ($access_policy == ACCESS_PRIVATE) {
            $ret['site']['access_policy'] = 'private';
        }
        if ($access_policy == ACCESS_PAID) {
            $ret['site']['access_policy'] = 'paid';
        }
        if ($access_policy == ACCESS_FREE) {
            $ret['site']['access_policy'] = 'free';
        }
        if ($access_policy == ACCESS_TIERED) {
            $ret['site']['access_policy'] = 'tiered';
        }
        $ret['site']['accounts'] = account_total();
        require_once 'include/identity.php';
        $ret['site']['channels'] = channel_total();
        $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']';
        $ret['site']['admin'] = get_config('system', 'admin_email');
        $visible_plugins = array();
        if (is_array($a->plugins) && count($a->plugins)) {
            $r = q("select * from addon where hidden = 0");
            if ($r) {
                foreach ($r as $rr) {
                    $visible_plugins[] = $rr['name'];
                }
            }
        }
        $ret['site']['plugins'] = $visible_plugins;
        $ret['site']['sitehash'] = get_config('system', 'location_hash');
        $ret['site']['sitename'] = get_config('system', 'sitename');
        $ret['site']['sellpage'] = get_config('system', 'sellpage');
        $ret['site']['location'] = get_config('system', 'site_location');
        $ret['site']['realm'] = get_directory_realm();
    }
    call_hooks('zot_finger', $ret);
    json_return_and_die($ret);
}
示例#22
0
文件: zot.php 项目: 23n/hubzilla
function check_zotinfo($channel, $locations, &$ret)
{
    //	logger('locations: ' . print_r($locations,true),LOGGER_DATA);
    // This function will likely expand as we find more things to detect and fix.
    // 1. Because magic-auth is reliant on it, ensure that the system channel has a valid hubloc
    //    Force this to be the case if anything is found to be wrong with it.
    // @FIXME ensure that the system channel exists in the first place and has an xchan
    if ($channel['channel_system']) {
        // the sys channel must have a location (hubloc)
        $valid_location = false;
        if (count($locations) === 1 && $locations[0]['primary'] && !$locations[0]['deleted']) {
            if (rsa_verify($locations[0]['url'], base64url_decode($locations[0]['url_sig']), $channel['channel_pubkey']) && $locations[0]['sitekey'] === get_config('system', 'pubkey') && $locations[0]['url'] === z_root()) {
                $valid_location = true;
            } else {
                logger('sys channel: invalid url signature');
            }
        }
        if (!$locations || !$valid_location) {
            logger('System channel locations are not valid. Attempting repair.');
            // Don't trust any existing records. Just get rid of them, but only do this
            // for the sys channel as normal channels will be trickier.
            q("delete from hubloc where hubloc_hash = '%s'", dbesc($channel['channel_hash']));
            $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_primary,\n\t\t\t\thubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_network )\n\t\t\t\tvalues ( '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s' )", dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_hash']), dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), intval(1), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $channel['channel_prvkey']))), dbesc(get_app()->get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system', 'pubkey')), dbesc('zot'));
            if ($r) {
                $x = zot_encode_locations($channel);
                if ($x) {
                    $ret['locations'] = $x;
                }
            } else {
                logger('Unable to store sys hub location');
            }
        }
    }
}
示例#23
0
 function import_account($account_id)
 {
     if (!$account_id) {
         logger("import_account: No account ID supplied");
         return;
     }
     $max_identities = account_service_class_fetch($account_id, 'total_identities');
     $max_friends = account_service_class_fetch($account_id, 'total_channels');
     $max_feeds = account_service_class_fetch($account_id, 'total_feeds');
     if ($max_identities !== false) {
         $r = q("select channel_id from channel where channel_account_id = %d", intval($account_id));
         if ($r && count($r) > $max_identities) {
             notice(sprintf(t('Your service plan only allows %d channels.'), $max_identities) . EOL);
             return;
         }
     }
     $data = null;
     $seize = x($_REQUEST, 'make_primary') ? intval($_REQUEST['make_primary']) : 0;
     $import_posts = x($_REQUEST, 'import_posts') ? intval($_REQUEST['import_posts']) : 0;
     $src = $_FILES['filename']['tmp_name'];
     $filename = basename($_FILES['filename']['name']);
     $filesize = intval($_FILES['filename']['size']);
     $filetype = $_FILES['filename']['type'];
     $completed = array_key_exists('import_step', $_SESSION) ? intval($_SESSION['import_step']) : 0;
     if ($completed) {
         logger('saved import step: ' . $_SESSION['import_step']);
     }
     if ($src) {
         // This is OS specific and could also fail if your tmpdir isn't very large
         // mostly used for Diaspora which exports gzipped files.
         if (strpos($filename, '.gz')) {
             @rename($src, $src . '.gz');
             @system('gunzip ' . escapeshellarg($src . '.gz'));
         }
         if ($filesize) {
             $data = @file_get_contents($src);
         }
         unlink($src);
     }
     if (!$src) {
         $old_address = x($_REQUEST, 'old_address') ? $_REQUEST['old_address'] : '';
         if (!$old_address) {
             logger('mod_import: nothing to import.');
             notice(t('Nothing to import.') . EOL);
             return;
         }
         $email = x($_REQUEST, 'email') ? $_REQUEST['email'] : '';
         $password = x($_REQUEST, 'password') ? $_REQUEST['password'] : '';
         $channelname = substr($old_address, 0, strpos($old_address, '@'));
         $servername = substr($old_address, strpos($old_address, '@') + 1);
         $scheme = 'https://';
         $api_path = '/api/red/channel/export/basic?f=&channel=' . $channelname;
         if ($import_posts) {
             $api_path .= '&posts=1';
         }
         $binary = false;
         $redirects = 0;
         $opts = array('http_auth' => $email . ':' . $password);
         $url = $scheme . $servername . $api_path;
         $ret = z_fetch_url($url, $binary, $redirects, $opts);
         if (!$ret['success']) {
             $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts);
         }
         if ($ret['success']) {
             $data = $ret['body'];
         } else {
             notice(t('Unable to download data from old server') . EOL);
         }
     }
     if (!$data) {
         logger('mod_import: empty file.');
         notice(t('Imported file is empty.') . EOL);
         return;
     }
     $data = json_decode($data, true);
     //	logger('import: data: ' . print_r($data,true));
     //	print_r($data);
     if (array_key_exists('user', $data) && array_key_exists('version', $data)) {
         require_once 'include/Import/import_diaspora.php';
         import_diaspora($data);
         return;
     }
     $moving = false;
     if (array_key_exists('compatibility', $data) && array_key_exists('database', $data['compatibility'])) {
         $v1 = substr($data['compatibility']['database'], -4);
         $v2 = substr(DB_UPDATE_VERSION, -4);
         if ($v2 > $v1) {
             $t = sprintf(t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1);
             notice($t);
         }
         if (array_key_exists('server_role', $data['compatibility']) && $data['compatibility']['server_role'] == 'basic') {
             $moving = true;
         }
     }
     if ($moving) {
         $seize = 1;
     }
     // import channel
     $relocate = array_key_exists('relocate', $data) ? $data['relocate'] : null;
     if (array_key_exists('channel', $data)) {
         if ($completed < 1) {
             $channel = import_channel($data['channel'], $account_id, $seize);
         } else {
             $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", intval($account_id), dbesc($channel['channel_guid']));
             if ($r) {
                 $channel = $r[0];
             }
         }
         if (!$channel) {
             logger('mod_import: channel not found. ', print_r($channel, true));
             notice(t('Cloned channel not found. Import failed.') . EOL);
             return;
         }
     }
     if (!$channel) {
         $channel = \App::get_channel();
     }
     if (!$channel) {
         logger('mod_import: channel not found. ', print_r($channel, true));
         notice(t('No channel. Import failed.') . EOL);
         return;
     }
     if ($completed < 2) {
         if (is_array($data['config'])) {
             import_config($channel, $data['config']);
         }
         logger('import step 2');
         $_SESSION['import_step'] = 2;
     }
     if ($completed < 3) {
         if ($data['photo']) {
             require_once 'include/photo/photo_driver.php';
             import_channel_photo(base64url_decode($data['photo']['data']), $data['photo']['type'], $account_id, $channel['channel_id']);
         }
         if (is_array($data['profile'])) {
             import_profiles($channel, $data['profile']);
         }
         logger('import step 3');
         $_SESSION['import_step'] = 3;
     }
     if ($completed < 4) {
         if (is_array($data['hubloc']) && !$moving) {
             import_hublocs($channel, $data['hubloc'], $seize);
         }
         logger('import step 4');
         $_SESSION['import_step'] = 4;
     }
     if ($completed < 5) {
         // create new hubloc for the new channel at this site
         $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_primary, \n\t\t\t\thubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey )\n\t\t\t\tvalues ( '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )", dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_hash']), dbesc(channel_reddress($channel)), dbesc('zot'), intval($seize ? 1 : 0), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(), $channel['channel_prvkey']))), dbesc(\App::get_hostname()), dbesc(z_root() . '/post'), dbesc(get_config('system', 'pubkey')));
         // reset the original primary hubloc if it is being seized
         if ($seize) {
             $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ", dbesc($channel['channel_hash']), dbesc(z_root()));
         }
         logger('import step 5');
         $_SESSION['import_step'] = 5;
     }
     if ($completed < 6) {
         // import xchans and contact photos
         if ($seize) {
             // replace any existing xchan we may have on this site if we're seizing control
             $r = q("delete from xchan where xchan_hash = '%s'", dbesc($channel['channel_hash']));
             $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_hidden, xchan_orphan, xchan_censored, xchan_selfcensored, xchan_system, xchan_pubforum, xchan_deleted ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d )", dbesc($channel['channel_hash']), dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_pubkey']), dbesc(z_root() . "/photo/profile/l/" . $channel['channel_id']), dbesc(z_root() . "/photo/profile/m/" . $channel['channel_id']), dbesc(z_root() . "/photo/profile/s/" . $channel['channel_id']), dbesc(channel_reddress($channel)), dbesc(z_root() . '/channel/' . $channel['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $channel['channel_address']), dbesc($channel['channel_name']), dbesc('zot'), dbesc(datetime_convert()), dbesc(datetime_convert()), 0, 0, 0, 0, 0, 0, 0);
         }
         logger('import step 6');
         $_SESSION['import_step'] = 6;
     }
     if ($completed < 7) {
         $xchans = $data['xchan'];
         if ($xchans) {
             foreach ($xchans as $xchan) {
                 $hash = make_xchan_hash($xchan['xchan_guid'], $xchan['xchan_guid_sig']);
                 if ($xchan['xchan_network'] === 'zot' && $hash !== $xchan['xchan_hash']) {
                     logger('forged xchan: ' . print_r($xchan, true));
                     continue;
                 }
                 if (!array_key_exists('xchan_hidden', $xchan)) {
                     $xchan['xchan_hidden'] = $xchan['xchan_flags'] & 0x1 ? 1 : 0;
                     $xchan['xchan_orphan'] = $xchan['xchan_flags'] & 0x2 ? 1 : 0;
                     $xchan['xchan_censored'] = $xchan['xchan_flags'] & 0x4 ? 1 : 0;
                     $xchan['xchan_selfcensored'] = $xchan['xchan_flags'] & 0x8 ? 1 : 0;
                     $xchan['xchan_system'] = $xchan['xchan_flags'] & 0x10 ? 1 : 0;
                     $xchan['xchan_pubforum'] = $xchan['xchan_flags'] & 0x20 ? 1 : 0;
                     $xchan['xchan_deleted'] = $xchan['xchan_flags'] & 0x1000 ? 1 : 0;
                 }
                 $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", dbesc($xchan['xchan_hash']));
                 if ($r) {
                     continue;
                 }
                 dbesc_array($xchan);
                 $r = dbq("INSERT INTO xchan (`" . implode("`, `", array_keys($xchan)) . "`) VALUES ('" . implode("', '", array_values($xchan)) . "')");
                 require_once 'include/photo/photo_driver.php';
                 $photos = import_xchan_photo($xchan['xchan_photo_l'], $xchan['xchan_hash']);
                 if ($photos[4]) {
                     $photodate = NULL_DATE;
                 } else {
                     $photodate = $xchan['xchan_photo_date'];
                 }
                 $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s'\n\t\t\t\t\t\twhere xchan_hash = '%s'", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc($photos[3]), dbesc($photodate), dbesc($xchan['xchan_hash']));
             }
         }
         logger('import step 7');
         $_SESSION['import_step'] = 7;
     }
     // FIXME - ensure we have an xchan if somebody is trying to pull a fast one
     if ($completed < 8) {
         $friends = 0;
         $feeds = 0;
         // import contacts
         $abooks = $data['abook'];
         if ($abooks) {
             foreach ($abooks as $abook) {
                 $abook_copy = $abook;
                 $abconfig = null;
                 if (array_key_exists('abconfig', $abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) {
                     $abconfig = $abook['abconfig'];
                 }
                 unset($abook['abook_id']);
                 unset($abook['abook_rating']);
                 unset($abook['abook_rating_text']);
                 unset($abook['abconfig']);
                 unset($abook['abook_their_perms']);
                 unset($abook['abook_my_perms']);
                 $abook['abook_account'] = $account_id;
                 $abook['abook_channel'] = $channel['channel_id'];
                 if (!array_key_exists('abook_blocked', $abook)) {
                     $abook['abook_blocked'] = $abook['abook_flags'] & 0x1 ? 1 : 0;
                     $abook['abook_ignored'] = $abook['abook_flags'] & 0x2 ? 1 : 0;
                     $abook['abook_hidden'] = $abook['abook_flags'] & 0x4 ? 1 : 0;
                     $abook['abook_archived'] = $abook['abook_flags'] & 0x8 ? 1 : 0;
                     $abook['abook_pending'] = $abook['abook_flags'] & 0x10 ? 1 : 0;
                     $abook['abook_unconnected'] = $abook['abook_flags'] & 0x20 ? 1 : 0;
                     $abook['abook_self'] = $abook['abook_flags'] & 0x80 ? 1 : 0;
                     $abook['abook_feed'] = $abook['abook_flags'] & 0x100 ? 1 : 0;
                 }
                 if ($abook['abook_self']) {
                     $role = get_pconfig($channel['channel_id'], 'system', 'permissions_role');
                     if ($role === 'forum' || $abook['abook_my_perms'] & PERMS_W_TAGWALL) {
                         q("update xchan set xchan_pubforum = 1 where xchan_hash = '%s' ", dbesc($abook['abook_xchan']));
                     }
                 } else {
                     if ($max_friends !== false && $friends > $max_friends) {
                         continue;
                     }
                     if ($max_feeds !== false && intval($abook['abook_feed']) && $feeds > $max_feeds) {
                         continue;
                     }
                 }
                 dbesc_array($abook);
                 $r = dbq("INSERT INTO abook (`" . implode("`, `", array_keys($abook)) . "`) VALUES ('" . implode("', '", array_values($abook)) . "')");
                 $friends++;
                 if (intval($abook['abook_feed'])) {
                     $feeds++;
                 }
                 translate_abook_perms_inbound($channel, $abook_copy);
                 if ($abconfig) {
                     // @fixme does not handle sync of del_abconfig
                     foreach ($abconfig as $abc) {
                         set_abconfig($channel['channel_id'], $abc['xchan'], $abc['cat'], $abc['k'], $abc['v']);
                     }
                 }
             }
         }
         logger('import step 8');
         $_SESSION['import_step'] = 8;
     }
     if ($completed < 9) {
         $groups = $data['group'];
         if ($groups) {
             $saved = array();
             foreach ($groups as $group) {
                 $saved[$group['hash']] = array('old' => $group['id']);
                 if (array_key_exists('name', $group)) {
                     $group['gname'] = $group['name'];
                     unset($group['name']);
                 }
                 unset($group['id']);
                 $group['uid'] = $channel['channel_id'];
                 dbesc_array($group);
                 $r = dbq("INSERT INTO groups (`" . implode("`, `", array_keys($group)) . "`) VALUES ('" . implode("', '", array_values($group)) . "')");
             }
             $r = q("select * from `groups` where uid = %d", intval($channel['channel_id']));
             if ($r) {
                 foreach ($r as $rr) {
                     $saved[$rr['hash']]['new'] = $rr['id'];
                 }
             }
         }
         $group_members = $data['group_member'];
         if ($group_members) {
             foreach ($group_members as $group_member) {
                 unset($group_member['id']);
                 $group_member['uid'] = $channel['channel_id'];
                 foreach ($saved as $x) {
                     if ($x['old'] == $group_member['gid']) {
                         $group_member['gid'] = $x['new'];
                     }
                 }
                 dbesc_array($group_member);
                 $r = dbq("INSERT INTO group_member (`" . implode("`, `", array_keys($group_member)) . "`) VALUES ('" . implode("', '", array_values($group_member)) . "')");
             }
         }
         logger('import step 9');
         $_SESSION['import_step'] = 9;
     }
     if (is_array($data['obj'])) {
         import_objs($channel, $data['obj']);
     }
     if (is_array($data['likes'])) {
         import_likes($channel, $data['likes']);
     }
     if (is_array($data['app'])) {
         import_apps($channel, $data['app']);
     }
     if (is_array($data['chatroom'])) {
         import_chatrooms($channel, $data['chatroom']);
     }
     if (is_array($data['conv'])) {
         import_conv($channel, $data['conv']);
     }
     if (is_array($data['mail'])) {
         import_mail($channel, $data['mail']);
     }
     if (is_array($data['event'])) {
         import_events($channel, $data['event']);
     }
     if (is_array($data['event_item'])) {
         import_items($channel, $data['event_item'], false, $relocate);
     }
     if (is_array($data['menu'])) {
         import_menus($channel, $data['menu']);
     }
     $addon = array('channel' => $channel, 'data' => $data);
     call_hooks('import_channel', $addon);
     $saved_notification_flags = notifications_off($channel['channel_id']);
     if ($import_posts && array_key_exists('item', $data) && $data['item']) {
         import_items($channel, $data['item'], false, $relocate);
     }
     notifications_on($channel['channel_id'], $saved_notification_flags);
     if (array_key_exists('item_id', $data) && $data['item_id']) {
         import_item_ids($channel, $data['item_id']);
     }
     // FIXME - ensure we have a self entry if somebody is trying to pull a fast one
     // send out refresh requests
     // notify old server that it may no longer be primary.
     \Zotlabs\Daemon\Master::Summon(array('Notifier', 'location', $channel['channel_id']));
     // This will indirectly perform a refresh_all *and* update the directory
     \Zotlabs\Daemon\Master::Summon(array('Directory', $channel['channel_id']));
     notice(t('Import completed.') . EOL);
     change_channel($channel['channel_id']);
     unset($_SESSION['import_step']);
     goaway(z_root() . '/network');
 }
示例#24
0
function randpost_fetch(&$a, &$b)
{
    $fort_server = get_config('fortunate', 'server');
    if (!$fort_server) {
        return;
    }
    $r = q("select * from pconfig where cat = 'randpost' and k = 'enable'");
    if ($r) {
        foreach ($r as $rr) {
            if (!$rr['v']) {
                continue;
            }
            //			logger('randpost');
            // cronhooks run every 10-15 minutes typically
            // try to keep from posting frequently.
            $test = mt_rand(0, 100);
            if ($test == 25) {
                $c = q("select * from channel where channel_id = %d limit 1", intval($rr['uid']));
                if (!$c) {
                    continue;
                }
                $mention = '';
                require_once 'include/html2bbcode.php';
                $s = z_fetch_url('http://' . $fort_server . '/cookie.php?numlines=2&equal=1&rand=' . mt_rand());
                if (!$s['success']) {
                    continue;
                }
                $x = array();
                $x['uid'] = $c[0]['channel_id'];
                $x['aid'] = $c[0]['channel_account_id'];
                $x['mid'] = $x['parent_mid'] = item_message_id();
                $x['author_xchan'] = $x['owner_xchan'] = $c[0]['channel_hash'];
                $x['item_thread_top'] = 1;
                $x['item_origin'] = 1;
                $x['item_verified'] = 1;
                $x['item_wall'] = 1;
                // if it might be a quote make it a quote
                if (strpos($s['body'], '--')) {
                    $x['body'] = $mention . '[quote]' . html2bbcode($s['body']) . '[/quote]';
                } else {
                    $x['body'] = $mention . html2bbcode($s['body']);
                }
                $x['sig'] = base64url_encode(rsa_sign($x['body'], $c[0]['channel_prvkey']));
                $post = item_store($x);
                $post_id = $post['item_id'];
                $x['id'] = $post_id;
                call_hooks('post_local_end', $x);
                Zotlabs\Daemon\Master::Summon(array('Notifier', 'wall-new', $post_id));
            }
        }
    }
}
示例#25
0
文件: item.php 项目: strk/friendica
function store_diaspora_comment_sig($datarray, $author, $uprvkey, $parent_item, $post_id)
{
    // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('mod_item: diaspora support disabled, not storing comment signature', LOGGER_DEBUG);
        return;
    }
    logger('mod_item: storing diaspora comment signature');
    require_once 'include/bb2diaspora.php';
    $signed_body = html_entity_decode(bb2diaspora($datarray['body']));
    // Only works for NETWORK_DFRN
    $contact_baseurl_start = strpos($author['url'], '://') + 3;
    $contact_baseurl_length = strpos($author['url'], '/profile') - $contact_baseurl_start;
    $contact_baseurl = substr($author['url'], $contact_baseurl_start, $contact_baseurl_length);
    $diaspora_handle = $author['nick'] . '@' . $contact_baseurl;
    $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $diaspora_handle;
    if ($uprvkey !== false) {
        $authorsig = base64_encode(rsa_sign($signed_text, $uprvkey, 'sha256'));
    } else {
        $authorsig = '';
    }
    q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), dbesc($signed_text), dbesc(base64_encode($authorsig)), dbesc($diaspora_handle));
    return;
}
示例#26
0
function diaspora_send_mail($item, $owner, $contact)
{
    $a = get_app();
    $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname();
    $r = q("select * from conv where id = %d and uid = %d limit 1", intval($item['convid']), intval($item['channel_id']));
    if (!count($r)) {
        logger('diaspora_send_mail: conversation not found.');
        return;
    }
    $cnv = $r[0];
    $conv = array('guid' => xmlify($cnv['guid']), 'subject' => xmlify($cnv['subject']), 'created_at' => xmlify(datetime_convert('UTC', 'UTC', $cnv['created'], 'Y-m-d H:i:s \\U\\T\\C')), 'diaspora_handle' => xmlify($cnv['creator']), 'participant_handles' => xmlify($cnv['recips']));
    if (array_key_exists('mail_flags', $item) && $item['mail_flags'] & MAIL_OBSCURED) {
        $key = get_config('system', 'prvkey');
        //		if($item['title'])
        //			$item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key);
        if ($item['body']) {
            $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']), $key);
        }
    }
    $body = bb2diaspora($item['body']);
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    $signed_text = $item['mid'] . ';' . $cnv['guid'] . ';' . $body . ';' . $created . ';' . $myaddr . ';' . $cnv['guid'];
    $sig = base64_encode(rsa_sign($signed_text, $owner['channel_prvkey'], 'sha256'));
    $msg = array('guid' => xmlify($item['mid']), 'parent_guid' => xmlify($cnv['guid']), 'parent_author_signature' => $item['reply'] ? null : xmlify($sig), 'author_signature' => xmlify($sig), 'text' => xmlify($body), 'created_at' => xmlify($created), 'diaspora_handle' => xmlify($myaddr), 'conversation_guid' => xmlify($cnv['guid']));
    if ($item['reply']) {
        $tpl = get_markup_template('diaspora_message.tpl');
        $xmsg = replace_macros($tpl, array('$msg' => $msg));
    } else {
        $conv['messages'] = array($msg);
        $tpl = get_markup_template('diaspora_conversation.tpl');
        $xmsg = replace_macros($tpl, array('$conv' => $conv));
    }
    logger('diaspora_conversation: ' . print_r($xmsg, true), LOGGER_DATA);
    $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg, $owner, $contact, $owner['channel_prvkey'], $contact['xchan_pubkey'], false)));
    return diaspora_transmit($owner, $contact, $slap, false);
}
示例#27
0
function diaspora_send_mail($item, $owner, $contact)
{
    $a = get_app();
    $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3);
    $r = q("select * from conv where id = %d and uid = %d limit 1", intval($item['convid']), intval($item['uid']));
    if (!count($r)) {
        logger('diaspora_send_mail: conversation not found.');
        return;
    }
    $cnv = $r[0];
    $conv = array('guid' => xmlify($cnv['guid']), 'subject' => xmlify($cnv['subject']), 'created_at' => xmlify(datetime_convert('UTC', 'UTC', $cnv['created'], 'Y-m-d H:i:s \\U\\T\\C')), 'diaspora_handle' => xmlify($cnv['creator']), 'participant_handles' => xmlify($cnv['recips']));
    $body = bb2diaspora($item['body']);
    $created = datetime_convert('UTC', 'UTC', $item['created'], 'Y-m-d H:i:s \\U\\T\\C');
    $signed_text = $item['guid'] . ';' . $cnv['guid'] . ';' . $body . ';' . $created . ';' . $myaddr . ';' . $cnv['guid'];
    $sig = base64_encode(rsa_sign($signed_text, $owner['uprvkey'], 'sha256'));
    $msg = array('guid' => xmlify($item['guid']), 'parent_guid' => xmlify($cnv['guid']), 'parent_author_signature' => xmlify($sig), 'author_signature' => xmlify($sig), 'text' => xmlify($body), 'created_at' => xmlify($created), 'diaspora_handle' => xmlify($myaddr), 'conversation_guid' => xmlify($cnv['guid']));
    if ($item['reply']) {
        $tpl = get_markup_template('diaspora_message.tpl');
        $xmsg = replace_macros($tpl, array('$msg' => $msg));
    } else {
        $conv['messages'] = array($msg);
        $tpl = get_markup_template('diaspora_conversation.tpl');
        $xmsg = replace_macros($tpl, array('$conv' => $conv));
    }
    logger('diaspora_conversation: ' . print_r($xmsg, true), LOGGER_DATA);
    $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], false)));
    //$slap = 'xml=' . urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],false));
    return diaspora_transmit($owner, $contact, $slap, false);
}
示例#28
0
文件: items.php 项目: Mauru/red
function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id)
{
    // We won't be able to sign Diaspora comments for authenticated visitors
    // - we don't have their private key
    // since Diaspora doesn't handle edits we can only do this for the original text and not update it.
    $enabled = intval(get_config('system', 'diaspora_enabled'));
    if (!$enabled) {
        logger('mod_item: diaspora support disabled, not storing comment signature', LOGGER_DEBUG);
        return;
    }
    $body = $datarray['body'];
    if (array_key_exists('item_flags', $datarray) && $datarray['item_flags'] & ITEM_OBSCURED) {
        $key = get_config('system', 'prvkey');
        if ($datarray['body']) {
            $body = crypto_unencapsulate(json_decode($datarray['body'], true), $key);
        }
    }
    logger('mod_item: storing diaspora comment signature', LOGGER_DEBUG);
    require_once 'include/bb2diaspora.php';
    $signed_body = html_entity_decode(bb2diaspora($body));
    $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname();
    $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
    if ($uprvkey !== false) {
        $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256'));
    } else {
        $authorsig = '';
    }
    $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig));
    $r = q("update item set diaspora_meta = '%s' where id = %d limit 1", dbesc(json_encode($x)), intval($post_id));
    $r = q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), dbesc($signed_text), dbesc(base64_encode($authorsig)), dbesc($diaspora_handle));
    if (!$r) {
        logger('store_diaspora_comment_sig: DB write failed');
    }
    return;
}
示例#29
0
function slapper($owner, $url, $slap)
{
    // does contact have a salmon endpoint?
    if (!strlen($url)) {
        return;
    }
    if (!$owner['channel_prvkey']) {
        logger(sprintf("channel '%s' (%d) does not have a salmon private key. Send failed.", $owner['channel_address'], $owner['channel_id']));
        return;
    }
    logger('slapper called for ' . $url . '. Data: ' . $slap, LOGGER_DATA, LOG_DEBUG);
    // create a magic envelope
    $data = base64url_encode($slap, false);
    // do not strip padding
    $data_type = 'application/atom+xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $keyhash = base64url_encode(hash('sha256', salmon_key($owner['channel_pubkey'])), true);
    $data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $data);
    // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign($data . $precomputed, $owner['channel_prvkey']));
    $salmon_tpl = get_markup_template('magicsig.tpl', 'addon/gnusoc/');
    $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature));
    logger('salmon: ' . $salmon, LOGGER_DATA);
    $hash = random_string();
    queue_insert(array('hash' => $hash, 'account_id' => $owner['channel_account_id'], 'channel_id' => $owner['channel_id'], 'driver' => 'slap', 'posturl' => $url, 'notify' => '', 'msg' => $salmon));
    return $hash;
}
示例#30
0
function fix_system_urls($oldurl, $newurl)
{
    require_once 'include/crypto.php';
    logger('fix_system_urls: renaming ' . $oldurl . '  to ' . $newurl);
    // Basically a site rename, but this can happen if you change from http to https for instance - even if the site name didn't change
    // This should fix URL changes on our site, but other sites will end up with orphan hublocs which they will try to contact and will
    // cause wasted communications.
    // What we need to do after fixing this up is to send a revocation of the old URL to every other site that we communicate with so
    // that they can clean up their hubloc tables (this includes directories).
    // It's a very expensive operation so you don't want to have to do it often or after your site gets to be large.
    $r = q("select xchan.*, hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url like '%s'", dbesc($oldurl . '%'));
    if ($r) {
        foreach ($r as $rr) {
            $channel_address = substr($rr['hubloc_addr'], 0, strpos($rr['hubloc_addr'], '@'));
            // get the associated channel. If we don't have a local channel, do nothing for this entry.
            $c = q("select * from channel where channel_hash = '%s' limit 1", dbesc($rr['hubloc_hash']));
            if (!$c) {
                continue;
            }
            $parsed = @parse_url($newurl);
            if (!$parsed) {
                continue;
            }
            $newhost = $parsed['host'];
            // sometimes parse_url returns unexpected results.
            if (strpos($newhost, '/') !== false) {
                $newhost = substr($newhost, 0, strpos($newhost, '/'));
            }
            $rhs = $newhost . ($parsed['port'] ? ':' . $parsed['port'] : '');
            // paths aren't going to work. You have to be at the (sub)domain root
            // . (($parsed['path']) ? $parsed['path'] : '');
            // The xchan_url might point to another nomadic identity clone
            $replace_xchan_url = strpos($rr['xchan_url'], $oldurl) !== false ? true : false;
            $x = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'", dbesc($channel_address . '@' . $rhs), dbesc($replace_xchan_url ? str_replace($oldurl, $newurl, $rr['xchan_url']) : $rr['xchan_url']), dbesc(str_replace($oldurl, $newurl, $rr['xchan_connurl'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_follow'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_connpage'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_photo_l'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_photo_m'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_photo_s'])), dbesc(datetime_convert()), dbesc($rr['xchan_hash']));
            $y = q("update hubloc set hubloc_addr = '%s', hubloc_url = '%s', hubloc_url_sig = '%s', hubloc_host = '%s', hubloc_callback = '%s' where hubloc_hash = '%s' and hubloc_url = '%s'", dbesc($channel_address . '@' . $rhs), dbesc($newurl), dbesc(base64url_encode(rsa_sign($newurl, $c[0]['channel_prvkey']))), dbesc($newhost), dbesc($newurl . '/post'), dbesc($rr['xchan_hash']), dbesc($oldurl));
            $z = q("update profile set photo = '%s', thumb = '%s' where uid = %d", dbesc(str_replace($oldurl, $newurl, $rr['xchan_photo_l'])), dbesc(str_replace($oldurl, $newurl, $rr['xchan_photo_m'])), intval($c[0]['channel_id']));
            proc_run('php', 'include/notifier.php', 'refresh_all', $c[0]['channel_id']);
        }
    }
}