Example #1
2
/**
 * API Login via basic-auth or OAuth
 */
function api_login(&$a)
{
    $record = null;
    require_once 'include/oauth.php';
    // login with oauth
    try {
        $oauth = new ZotOAuth1();
        $req = OAuth1Request::from_request();
        list($consumer, $token) = $oauth->verify_request($req);
        if (!is_null($token)) {
            $oauth->loginUser($token->uid);
            App::set_oauth_key($consumer->key);
            call_hooks('logged_in', App::$user);
            return;
        }
        killme();
    } catch (Exception $e) {
        logger($e->getMessage());
    }
    // workarounds for HTTP-auth in CGI mode
    if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
        $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
        if (strlen($userpass)) {
            list($name, $password) = explode(':', $userpass);
            $_SERVER['PHP_AUTH_USER'] = $name;
            $_SERVER['PHP_AUTH_PW'] = $password;
        }
    }
    if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
        $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6));
        if (strlen($userpass)) {
            list($name, $password) = explode(':', $userpass);
            $_SERVER['PHP_AUTH_USER'] = $name;
            $_SERVER['PHP_AUTH_PW'] = $password;
        }
    }
    require_once 'include/auth.php';
    require_once 'include/security.php';
    // process normal login request
    if (isset($_SERVER['PHP_AUTH_USER'])) {
        $channel_login = 0;
        $record = account_verify_password($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
        if ($record && $record['channel']) {
            $channel_login = $record['channel']['channel_id'];
        }
    }
    if ($record['account']) {
        authenticate_success($record['account']);
        if ($channel_login) {
            change_channel($channel_login);
        }
        $_SESSION['allow_api'] = true;
        return true;
    } else {
        $_SERVER['PHP_AUTH_PW'] = '*****';
        logger('API_login failure: ' . print_r($_SERVER, true), LOGGER_DEBUG);
        log_failed_login('API login failure');
        retry_basic_auth();
    }
}
Example #2
0
/**
 * @param int $user_record The account_id
 * @param bool $login_initial default false
 * @param bool $interactive default false
 * @param bool $return
 * @param bool $update_lastlog
 */
function authenticate_success($user_record, $channel = null, $login_initial = false, $interactive = false, $return = false, $update_lastlog = false)
{
    $_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
    $lastlog_updated = false;
    if (x($user_record, 'account_id')) {
        App::$account = $user_record;
        $_SESSION['account_id'] = $user_record['account_id'];
        $_SESSION['authenticated'] = 1;
        if ($channel) {
            $uid_to_load = $channel['channel_id'];
        }
        if (!$uid_to_load) {
            $uid_to_load = x($_SESSION, 'uid') && intval($_SESSION['uid']) ? intval($_SESSION['uid']) : intval(App::$account['account_default_channel']);
        }
        if ($uid_to_load) {
            change_channel($uid_to_load);
        }
        if ($login_initial || $update_lastlog) {
            q("update account set account_lastlog = '%s' where account_id = %d", dbesc(datetime_convert()), intval($_SESSION['account_id']));
            App::$account['account_lastlog'] = datetime_convert();
            $lastlog_updated = true;
            call_hooks('logged_in', App::$account);
        }
    }
    if ($login_initial && !$lastlog_updated) {
        call_hooks('logged_in', $user_record);
        // might want to log success here
    }
    if ($return || x($_SESSION, 'workflow')) {
        unset($_SESSION['workflow']);
        return;
    }
    if (App::$module !== 'home' && x($_SESSION, 'login_return_url') && strlen($_SESSION['login_return_url'])) {
        $return_url = $_SESSION['login_return_url'];
        // don't let members get redirected to a raw ajax page update - this can happen
        // if DHCP changes the IP address at an unfortunate time and paranoia is turned on
        if (strstr($return_url, 'update_')) {
            $return_url = '';
        }
        unset($_SESSION['login_return_url']);
        goaway(z_root() . '/' . $return_url);
    }
    /* This account has never created a channel. Send them to new_channel by default */
    if (App::$module === 'login') {
        $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0 ", intval(App::$account['account_id']));
        if ($r && !$r[0]['total']) {
            goaway(z_root() . '/new_channel');
        }
    }
    /* else just return */
}
Example #3
0
function api_user()
{
    $aid = get_account_id();
    $channel = get_app()->get_channel();
    if ($aid && x($_REQUEST, 'channel')) {
        // Only change channel if it is different than the current channel
        if ($channel && x($channel, 'channel_address') && $channel['channel_address'] != $_REQUEST['channel']) {
            $c = q("select channel_id from channel where channel_address = '%s' and channel_account_id = %d limit 1", dbesc($_REQUEST['channel']), intval($aid));
            if (!$c || !change_channel($c[0]['channel_id'])) {
                return false;
            }
        }
    }
    if ($_SESSION["allow_api"]) {
        return local_channel();
    }
    return false;
}
Example #4
0
function new_channel_post(&$a)
{
    $arr = $_POST;
    if (($arr['account_id'] = get_account_id()) === false) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    $result = create_identity($arr);
    if (!$result['success']) {
        notice($result['message']);
        return;
    }
    $newuid = $result['channel']['channel_id'];
    change_channel($result['channel']['channel_id']);
    if (!strlen($next_page = get_config('system', 'workflow_channel_next'))) {
        $next_page = 'settings';
    }
    goaway(z_root() . '/' . $next_page);
}
Example #5
0
/** @file */
function authenticate_success($user_record, $login_initial = false, $interactive = false, $return = false, $update_lastlog = false)
{
    $a = get_app();
    $_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
    if (x($user_record, 'account_id')) {
        $a->account = $user_record;
        $_SESSION['account_id'] = $user_record['account_id'];
        $_SESSION['authenticated'] = 1;
        if ($login_initial || $update_lastlog) {
            q("update account set account_lastlog = '%s' where account_id = %d limit 1", dbesc(datetime_convert()), intval($_SESSION['account_id']));
            $a->account['account_lastlog'] = datetime_convert();
            call_hooks('logged_in', $a->account);
        }
        $uid_to_load = x($_SESSION, 'uid') && intval($_SESSION['uid']) ? intval($_SESSION['uid']) : intval($a->account['account_default_channel']);
        if ($uid_to_load) {
            change_channel($uid_to_load);
        }
    }
    if ($login_initial) {
        call_hooks('logged_in', $user_record);
        // might want to log success here
    }
    if ($return || x($_SESSION, 'workflow')) {
        unset($_SESSION['workflow']);
        return;
    }
    if ($a->module !== 'home' && x($_SESSION, 'login_return_url') && strlen($_SESSION['login_return_url'])) {
        $return_url = $_SESSION['login_return_url'];
        unset($_SESSION['login_return_url']);
        goaway($a->get_baseurl() . '/' . $return_url);
    }
    /* This account has never created a channel. Send them to new_channel by default */
    if ($a->module === 'login') {
        $r = q("select count(channel_id) as total from channel where channel_account_id = %d and not ( channel_pageflags & %d)", intval($a->account['account_id']), intval(PAGE_REMOVED));
        if ($r && !$r[0]['total']) {
            goaway(z_root() . '/new_channel');
        }
    }
    /* else just return */
}
Example #6
0
function new_channel_post(&$a)
{
    $arr = $_POST;
    $acc = $a->get_account();
    $arr['account_id'] = get_account_id();
    // prevent execution by delegated channels as well as those not logged in.
    // get_account_id() returns the account_id from the session. But $a->account
    // may point to the original authenticated account.
    if (!$acc || $acc['account_id'] != $arr['account_id']) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    $result = create_identity($arr);
    if (!$result['success']) {
        notice($result['message']);
        return;
    }
    $newuid = $result['channel']['channel_id'];
    change_channel($result['channel']['channel_id']);
    if (!strlen($next_page = get_config('system', 'workflow_channel_next'))) {
        $next_page = 'settings';
    }
    goaway(z_root() . '/' . $next_page);
}
Example #7
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');
 }
Example #8
0
 function post()
 {
     $max_dailies = intval(get_config('system', 'max_daily_registrations'));
     if ($max_dailies) {
         $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", db_utcnow(), db_quoteinterval('1 day'));
         if ($r && $r[0]['total'] >= $max_dailies) {
             notice(t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL);
             return;
         }
     }
     if (!x($_POST, 'tos')) {
         notice(t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL);
         return;
     }
     $policy = get_config('system', 'register_policy');
     $email_verify = get_config('system', 'verify_email');
     switch ($policy) {
         case REGISTER_OPEN:
             $flags = ACCOUNT_OK;
             break;
         case REGISTER_APPROVE:
             $flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING;
             break;
         default:
         case REGISTER_CLOSED:
             if (!is_site_admin()) {
                 notice(t('Permission denied.') . EOL);
                 return;
             }
             $flags = ACCOUNT_BLOCKED;
             break;
     }
     if ($email_verify && $policy == REGISTER_OPEN) {
         $flags = $flags | ACCOUNT_UNVERIFIED;
     }
     if (!$_POST['password'] || $_POST['password'] !== $_POST['password2']) {
         notice(t('Passwords do not match.') . EOL);
         return;
     }
     $arr = $_POST;
     $arr['account_flags'] = $flags;
     $result = create_account($arr);
     if (!$result['success']) {
         notice($result['message']);
         return;
     }
     require_once 'include/security.php';
     if ($_REQUEST['name']) {
         set_aconfig($result['account']['account_id'], 'register', 'channel_name', $_REQUEST['name']);
     }
     if ($_REQUEST['nickname']) {
         set_aconfig($result['account']['account_id'], 'register', 'channel_address', $_REQUEST['nickname']);
     }
     if ($_REQUEST['permissions_role']) {
         set_aconfig($result['account']['account_id'], 'register', 'permissions_role', $_REQUEST['permissions_role']);
     }
     $using_invites = intval(get_config('system', 'invitation_only'));
     $num_invites = intval(get_config('system', 'number_invites'));
     $invite_code = x($_POST, 'invite_code') ? notags(trim($_POST['invite_code'])) : '';
     if ($using_invites && $invite_code) {
         q("delete * from register where hash = '%s'", dbesc($invite_code));
         // @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php
         set_aconfig($result['account']['account_id'], 'system', 'invites_remaining', $num_invites);
     }
     if ($policy == REGISTER_OPEN) {
         if ($email_verify) {
             $res = verify_email_address($result);
         } else {
             $res = send_register_success_email($result['email'], $result['password']);
         }
         if ($res) {
             info(t('Registration successful. Please check your email for validation instructions.') . EOL);
         }
     } elseif ($policy == REGISTER_APPROVE) {
         $res = send_reg_approval_email($result);
         if ($res) {
             info(t('Your registration is pending approval by the site owner.') . EOL);
         } else {
             notice(t('Your registration can not be processed.') . EOL);
         }
         goaway(z_root());
     }
     if ($email_verify) {
         goaway(z_root());
     }
     authenticate_success($result['account'], null, true, false, true);
     $new_channel = false;
     $next_page = 'new_channel';
     if (get_config('system', 'auto_channel_create') || UNO) {
         $new_channel = auto_channel_create($result['account']['account_id']);
         if ($new_channel['success']) {
             $channel_id = $new_channel['channel']['channel_id'];
             change_channel($channel_id);
             $next_page = '~';
         } else {
             $new_channel = false;
         }
     }
     $x = get_config('system', 'workflow_register_next');
     if ($x) {
         $next_page = $x;
         $_SESSION['workflow'] = true;
     }
     goaway(z_root() . '/' . $next_page);
 }
Example #9
0
 function Verify($channel, $hubloc)
 {
     logger('auth request received from ' . $hubloc['hubloc_addr']);
     $this->remote = remote_channel();
     $this->remote_service_class = '';
     $this->remote_level = 0;
     $this->remote_hub = $hubloc['hubloc_url'];
     $this->dnt = 0;
     // check credentials and access
     // If they are already authenticated and haven't changed credentials,
     // we can save an expensive network round trip and improve performance.
     // Also check that they are coming from the same site as they authenticated with originally.
     $already_authed = remote_channel() && $hubloc['hubloc_hash'] == remote_channel() && $hubloc['hubloc_url'] === $_SESSION['remote_hub'] ? true : false;
     if ($this->delegate && $this->delegate !== $_SESSION['delegate_channel']) {
         $already_authed = false;
     }
     if ($already_authed) {
         return true;
     }
     if (local_channel()) {
         // tell them to logout if they're logged in locally as anything but the target remote account
         // in which case just shut up because they don't need to be doing this at all.
         if (\App::$channel['channel_hash'] == $hubloc['xchan_hash']) {
             return true;
         } else {
             logger('already authenticated locally as somebody else.');
             notice(t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL);
             if ($this->test) {
                 $this->Debug('already logged in locally with a conflicting identity.');
                 return false;
             }
         }
         return false;
     }
     // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the
     // site private key
     // The actual channel sending the packet ($c[0]) is not important, but this provides a
     // generic zot packet with a sender which can be verified
     $p = zot_build_packet($channel, $type = 'auth_check', array(array('guid' => $hubloc['hubloc_guid'], 'guid_sig' => $hubloc['hubloc_guid_sig'])), $hubloc['hubloc_sitekey'], $this->sec);
     $this->Debug('auth check packet created using sitekey ' . $hubloc['hubloc_sitekey']);
     $this->Debug('packet contents: ' . $p);
     $result = zot_zot($hubloc['hubloc_callback'], $p);
     if (!$result['success']) {
         logger('auth_check callback failed.');
         if ($this->test) {
             $this->Debug('auth check request to your site returned .' . print_r($result, true));
         }
         return false;
     }
     $j = json_decode($result['body'], true);
     if (!$j) {
         logger('auth_check json data malformed.');
         if ($this->test) {
             $this->Debug('json malformed: ' . $result['body']);
         }
         return false;
     }
     $this->Debug('auth check request returned .' . print_r($j, true));
     if (!$j['success']) {
         return false;
     }
     // legit response, but we do need to check that this wasn't answered by a man-in-middle
     if (!rsa_verify($this->sec . $hubloc['xchan_hash'], base64url_decode($j['confirm']), $hubloc['xchan_pubkey'])) {
         logger('final confirmation failed.');
         if ($this->test) {
             $this->Debug('final confirmation failed. ' . $sec . print_r($j, true) . print_r($hubloc, true));
         }
         return false;
     }
     if (array_key_exists('service_class', $j)) {
         $this->remote_service_class = $j['service_class'];
     }
     if (array_key_exists('level', $j)) {
         $this->remote_level = $j['level'];
     }
     if (array_key_exists('DNT', $j)) {
         $this->dnt = $j['DNT'];
     }
     // log them in
     if ($this->test) {
         // testing only - return the success result
         $this->test_results['success'] = true;
         $this->Debug('Authentication Success!');
         $this->Finalise();
     }
     $_SESSION['authenticated'] = 1;
     // check for delegation and if all is well, log them in locally with delegation restrictions
     $this->delegate_success = false;
     if ($this->delegate) {
         $r = q("select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", dbesc($this->delegate));
         if ($r && intval($r[0]['channel_id'])) {
             $allowed = perm_is_allowed($r[0]['channel_id'], $hubloc['xchan_hash'], 'delegate');
             if ($allowed) {
                 $_SESSION['delegate_channel'] = $r[0]['channel_id'];
                 $_SESSION['delegate'] = $hubloc['xchan_hash'];
                 $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
                 require_once 'include/security.php';
                 // this will set the local_channel authentication in the session
                 change_channel($r[0]['channel_id']);
                 $this->delegate_success = true;
             }
         }
     }
     if (!$this->delegate_success) {
         // normal visitor (remote_channel) login session credentials
         $_SESSION['visitor_id'] = $hubloc['xchan_hash'];
         $_SESSION['my_url'] = $hubloc['xchan_url'];
         $_SESSION['my_address'] = $this->address;
         $_SESSION['remote_service_class'] = $this->remote_service_class;
         $_SESSION['remote_level'] = $this->remote_level;
         $_SESSION['remote_hub'] = $this->remote_hub;
         $_SESSION['DNT'] = $this->dnt;
     }
     $arr = array('xchan' => $hubloc, 'url' => $this->desturl, 'session' => $_SESSION);
     call_hooks('magic_auth_success', $arr);
     \App::set_observer($hubloc);
     require_once 'include/security.php';
     \App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
     info(sprintf(t('Welcome %s. Remote authentication successful.'), $hubloc['xchan_name']));
     logger('mod_zot: auth success from ' . $hubloc['xchan_addr']);
     $this->success = true;
     return true;
 }
Example #10
0
 function get()
 {
     if (!get_account_id() || $_SESSION['delegate']) {
         notice(t('Permission denied.') . EOL);
         return;
     }
     require_once 'include/security.php';
     $change_channel = argc() > 1 ? intval(argv(1)) : 0;
     if (argc() > 2 && argv(2) === 'default') {
         $r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1", intval($change_channel), intval(get_account_id()));
         if ($r) {
             q("update account set account_default_channel = %d where account_id = %d", intval($change_channel), intval(get_account_id()));
         }
         goaway(z_root() . '/manage');
     }
     if ($change_channel) {
         $r = change_channel($change_channel);
         if (argc() > 2 && !(argv(2) === 'default')) {
             goaway(z_root() . '/' . implode('/', array_slice(\App::$argv, 2)));
             // Go to whatever is after /manage/, but with the new channel
         } else {
             if ($r && $r['channel_startpage']) {
                 goaway(z_root() . '/' . $r['channel_startpage']);
             }
             // If nothing extra is specified, go to the default page
         }
         goaway(z_root());
     }
     $channels = null;
     if (local_channel()) {
         $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", intval(get_account_id()));
         $account = \App::get_account();
         if ($r && count($r)) {
             $channels = $r;
             for ($x = 0; $x < count($channels); $x++) {
                 $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']);
                 $channels[$x]['default'] = $channels[$x]['channel_id'] == $account['account_default_channel'] ? "1" : '';
                 $channels[$x]['default_links'] = '1';
                 $c = q("SELECT id, item_wall FROM item\n\t\t\t\t\t\tWHERE item_unseen = 1 and uid = %d " . item_normal(), intval($channels[$x]['channel_id']));
                 if ($c) {
                     foreach ($c as $it) {
                         if (intval($it['item_wall'])) {
                             $channels[$x]['home']++;
                         } else {
                             $channels[$x]['network']++;
                         }
                     }
                 }
                 $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", intval($channels[$x]['channel_id']));
                 if ($intr) {
                     $channels[$x]['intros'] = intval($intr[0]['total']);
                 }
                 $mails = q("SELECT count(id) as total from mail WHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ", intval($channels[$x]['channel_id']), dbesc($channels[$x]['channel_hash']));
                 if ($mails) {
                     $channels[$x]['mail'] = intval($mails[0]['total']);
                 }
                 $events = q("SELECT type, start, adjust FROM `event`\n\t\t\t\t\t\tWHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0\n\t\t\t\t\t\tORDER BY `start` ASC ", intval($channels[$x]['channel_id']), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')));
                 if ($events) {
                     $channels[$x]['all_events'] = count($events);
                     if ($channels[$x]['all_events']) {
                         $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
                         foreach ($events as $e) {
                             $bd = false;
                             if ($e['type'] === 'birthday') {
                                 $channels[$x]['birthdays']++;
                                 $bd = true;
                             } else {
                                 $channels[$x]['events']++;
                             }
                             if (datetime_convert('UTC', intval($e['adjust']) ? date_default_timezone_get() : 'UTC', $e['start'], 'Y-m-d') === $str_now) {
                                 $channels[$x]['all_events_today']++;
                                 if ($bd) {
                                     $channels[$x]['birthdays_today']++;
                                 } else {
                                     $channels[$x]['events_today']++;
                                 }
                             }
                         }
                     }
                 }
             }
         }
         $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0", intval(get_account_id()));
         $limit = account_service_class_fetch(get_account_id(), 'total_identities');
         if ($limit !== false) {
             $channel_usage_message = sprintf(t("You have created %1\$.0f of %2\$.0f allowed channels."), $r[0]['total'], $limit);
         } else {
             $channel_usage_message = '';
         }
     }
     $create = array('new_channel', t('Create a new channel'), t('Create New'));
     $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where \n\t\t\tabook_channel = %d and (abook_their_perms & %d) > 0", intval(local_channel()), intval(PERMS_A_DELEGATE));
     if ($delegates) {
         for ($x = 0; $x < count($delegates); $x++) {
             $delegates[$x]['link'] = 'magic?f=&dest=' . urlencode($delegates[$x]['xchan_url']) . '&delegate=' . urlencode($delegates[$x]['xchan_addr']);
             $delegates[$x]['channel_name'] = $delegates[$x]['xchan_name'];
             $delegates[$x]['delegate'] = 1;
         }
     } else {
         $delegates = null;
     }
     $o = replace_macros(get_markup_template('channels.tpl'), array('$header' => t('Channel Manager'), '$msg_selected' => t('Current Channel'), '$selected' => local_channel(), '$desc' => t('Switch to one of your channels by selecting it.'), '$msg_default' => t('Default Channel'), '$msg_make_default' => t('Make Default'), '$create' => $create, '$all_channels' => $channels, '$mail_format' => t('%d new messages'), '$intros_format' => t('%d new introductions'), '$channel_usage_message' => $channel_usage_message, '$delegated_desc' => t('Delegated Channel'), '$delegates' => $delegates));
     return $o;
 }
Example #11
0
File: manage.php Project: Mauru/red
function manage_content(&$a)
{
    if (!get_account_id()) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    require_once 'include/security.php';
    $change_channel = argc() > 1 ? intval(argv(1)) : 0;
    if (argc() > 2 && argv(2) === 'default') {
        $r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1", intval($change_channel), intval(get_account_id()));
        if ($r) {
            q("update account set account_default_channel = %d where account_id = %d limit 1", intval($change_channel), intval(get_account_id()));
        }
        goaway(z_root() . '/manage');
    }
    if ($change_channel) {
        $r = change_channel($change_channel);
        if ($r && $r['channel_startpage']) {
            goaway(z_root() . '/' . $r['channel_startpage']);
        }
        goaway(z_root());
    }
    $channels = null;
    if (local_user()) {
        $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and not ( channel_pageflags & %d ) order by channel_name ", intval(get_account_id()), intval(PAGE_REMOVED));
        $selected_channel = null;
        $account = get_app()->get_account();
        if ($r && count($r)) {
            $channels = $r;
            for ($x = 0; $x < count($channels); $x++) {
                $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']);
                if ($channels[$x]['channel_id'] == local_user()) {
                    $selected_channel = $channels[$x];
                }
                $channels[$x]['default'] = $channels[$x]['channel_id'] == $account['account_default_channel'] ? "1" : '';
                $channels[$x]['default_links'] = '1';
                $c = q("SELECT id, item_restrict, item_flags FROM item\n\t\t\t\t\tWHERE (item_restrict = %d) and ( item_flags & %d ) and uid = %d", intval(ITEM_VISIBLE), intval(ITEM_UNSEEN), intval($channels[$x]['channel_id']));
                if ($c) {
                    foreach ($c as $it) {
                        if ($it['item_flags'] & ITEM_WALL) {
                            $channels[$x]['home']++;
                        } else {
                            $channels[$x]['network']++;
                        }
                    }
                }
                $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and (abook_flags & %d) and not ((abook_flags & %d) or (xchan_flags & %d))", intval($channels[$x]['channel_id']), intval(ABOOK_FLAG_PENDING), intval(ABOOK_FLAG_SELF | ABOOK_FLAG_IGNORED), intval(XCHAN_FLAGS_DELETED | XCHAN_FLAGS_ORPHAN));
                if ($intr) {
                    $channels[$x]['intros'] = intval($intr[0]['total']);
                }
                $mails = q("SELECT count(id) as total from mail WHERE channel_id = %d AND not (mail_flags & %d) and from_xchan != '%s' ", intval($channels[$x]['channel_id']), intval(MAIL_SEEN), dbesc($channels[$x]['channel_hash']));
                if ($mails) {
                    $channels[$x]['mail'] = intval($mails[0]['total']);
                }
                $events = q("SELECT type, start, adjust FROM `event`\n\t\t\t\t\tWHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0\n\t\t\t\t\tORDER BY `start` ASC ", intval($channels[$x]['channel_id']), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')));
                if ($events) {
                    $channels[$x]['all_events'] = count($events);
                    if ($channels[$x]['all_events']) {
                        $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
                        foreach ($events as $e) {
                            $bd = false;
                            if ($e['type'] === 'birthday') {
                                $channels[$x]['birthdays']++;
                                $bd = true;
                            } else {
                                $channels[$x]['events']++;
                            }
                            if (datetime_convert('UTC', intval($e['adjust']) ? date_default_timezone_get() : 'UTC', $e['start'], 'Y-m-d') === $str_now) {
                                $channels[$x]['all_events_today']++;
                                if ($bd) {
                                    $channels[$x]['birthdays_today']++;
                                } else {
                                    $channels[$x]['events_today']++;
                                }
                            }
                        }
                    }
                }
            }
        }
        $r = q("select count(channel_id) as total from channel where channel_account_id = %d and not ( channel_pageflags & %d )", intval(get_account_id()), intval(PAGE_REMOVED));
        $limit = service_class_fetch(local_user(), 'total_identities');
        if ($limit !== false) {
            $channel_usage_message = sprintf(t("You have created %1\$.0f of %2\$.0f allowed channels."), $r[0]['total'], $limit);
        } else {
            $channel_usage_message = '';
        }
    }
    $links = array(array('new_channel', t('Create a new channel'), t('Create a new channel')));
    $o = replace_macros(get_markup_template('channels.tpl'), array('$header' => t('Channel Manager'), '$msg_selected' => t('Current Channel'), '$selected' => $selected_channel, '$desc' => t('Attach to one of your channels by selecting it.'), '$msg_default' => t('Default Channel'), '$msg_make_default' => t('Make Default'), '$links' => $links, '$all_channels' => $channels, '$channel_usage_message' => $channel_usage_message));
    return $o;
}
Example #12
0
function import_diaspora($data)
{
    $a = get_app();
    $account = $a->get_account();
    if (!$account) {
        return false;
    }
    $address = escape_tags($data['user']['username']);
    if (!$address) {
        notice(t('No username found in import file.') . EOL);
        return false;
    }
    $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($address));
    if ($r) {
        // try at most ten times to generate a unique address.
        $x = 0;
        $found_unique = false;
        do {
            $tmp = $address . mt_rand(1000, 9999);
            $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($tmp));
            if (!$r) {
                $address = $tmp;
                $found_unique = true;
                break;
            }
            $x++;
        } while ($x < 10);
        if (!$found_unique) {
            logger('import_diaspora: duplicate channel address. randomisation failed.');
            notice(t('Unable to create a unique channel address. Import failed.') . EOL);
            return;
        }
    }
    $c = create_identity(array('name' => escape_tags($data['user']['name']), 'nickname' => $address, 'account_id' => $account['account_id'], 'permissions_role' => 'social'));
    if (!$c['success']) {
        return;
    }
    $channel_id = $c['channel']['channel_id'];
    // todo - add auto follow settings, (and strip exif in hubzilla)
    $location = escape_tags($data['user']['profile']['location']);
    if (!$location) {
        $location = '';
    }
    q("update channel set channel_location = '%s' where channel_id = %d", dbesc($location), intval($channel_id));
    if ($data['user']['profile']['nsfw']) {
        // fixme for hubzilla which doesn't use pageflags any more
        q("update channel set channel_pageflags = (channel_pageflags | %d) where channel_id = %d", intval(PAGE_ADULT), intval($channel_id));
    }
    if ($data['user']['profile']['image_url']) {
        $p = z_fetch_url($data['user']['profile']['image_url'], true);
        if ($p['success']) {
            $rawbytes = $p['body'];
            $type = guess_image_type('dummyfile', $p['header']);
            import_channel_photo($rawbytes, $type, $c['channel']['channel_account_id'], $channel_id);
        }
    }
    $gender = escape_tags($data['user']['profile']['gender']);
    $about = diaspora2bb($data['user']['profile']['bio']);
    $publish = intval($data['user']['profile']['searchable']);
    if ($data['user']['profile']['birthday']) {
        $dob = datetime_convert('UTC', 'UTC', $data['user']['profile']['birthday'], 'Y-m-d');
    } else {
        $dob = '0000-00-00';
    }
    // we're relying on the fact that this channel was just created and will only
    // have the default profile currently
    $r = q("update profile set gender = '%s', about = '%s', dob = '%s', publish = %d where uid = %d", dbesc($gender), dbesc($about), dbesc($dob), dbesc($publish), intval($channel_id));
    if ($data['user']['aspects']) {
        foreach ($data['user']['aspects'] as $aspect) {
            group_add($channel_id, escape_tags($aspect['name']), intval($aspect['contacts_visible']));
        }
    }
    // now add connections and send friend requests
    if ($data['user']['contacts']) {
        foreach ($data['user']['contacts'] as $contact) {
            $result = new_contact($channel_id, $contact['person_diaspora_handle'], $c['channel']);
            if ($result['success']) {
                if ($contact['aspects']) {
                    foreach ($contact['aspects'] as $aspect) {
                        group_add_member($channel_id, $aspect['name'], $result['abook']['xchan_hash']);
                    }
                }
            }
        }
    }
    // Then add items - note this can't be done until Diaspora adds guids to exported
    // items and comments
    // This will indirectly perform a refresh_all *and* update the directory
    proc_run('php', 'include/directory.php', $channel_id);
    notice(t('Import completed.') . EOL);
    change_channel($channel_id);
    goaway(z_root() . '/network');
}
Example #13
0
/**
 * Simple HTTP Login
 */
function api_login(&$a)
{
    // login with oauth
    try {
        $oauth = new FKOAuth1();
        $req = OAuthRequest::from_request();
        list($consumer, $token) = $oauth->verify_request($req);
        //			list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
        if (!is_null($token)) {
            $oauth->loginUser($token->uid);
            $a->set_oauth_key($consumer->key);
            call_hooks('logged_in', $a->user);
            return;
        }
        echo __FILE__ . __LINE__ . __FUNCTION__ . "<pre>";
        //			var_dump($consumer, $token);
        die;
    } catch (Exception $e) {
        logger(__FILE__ . __LINE__ . __FUNCTION__ . "\n" . $e);
    }
    // workaround for HTTP-auth in CGI mode
    if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
        $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
        if (strlen($userpass)) {
            list($name, $password) = explode(':', $userpass);
            $_SERVER['PHP_AUTH_USER'] = $name;
            $_SERVER['PHP_AUTH_PW'] = $password;
        }
    }
    if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
        $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6));
        if (strlen($userpass)) {
            list($name, $password) = explode(':', $userpass);
            $_SERVER['PHP_AUTH_USER'] = $name;
            $_SERVER['PHP_AUTH_PW'] = $password;
        }
    }
    if (!isset($_SERVER['PHP_AUTH_USER'])) {
        logger('API_login: '******'WWW-Authenticate: Basic realm="Red"');
        header('HTTP/1.0 401 Unauthorized');
        die('This api requires login');
    }
    // process normal login request
    require_once 'include/auth.php';
    $channel_login = 0;
    $record = account_verify_password($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
    if (!$record) {
        $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($_SERVER['PHP_AUTH_USER']));
        if ($r) {
            $x = q("select * from account where account_id = %d limit 1", intval($r[0]['channel_account_id']));
            if ($x) {
                $record = account_verify_password($x[0]['account_email'], $_SERVER['PHP_AUTH_PW']);
                if ($record) {
                    $channel_login = $r[0]['channel_id'];
                }
            }
        }
        if (!$record) {
            logger('API_login failure: ' . print_r($_SERVER, true), LOGGER_DEBUG);
            header('WWW-Authenticate: Basic realm="Red"');
            header('HTTP/1.0 401 Unauthorized');
            die('This api requires login');
        }
    }
    require_once 'include/security.php';
    authenticate_success($record);
    if ($channel_login) {
        change_channel($channel_login);
    }
    $_SESSION['allow_api'] = true;
}
Example #14
0
function import_post(&$a)
{
    $account_id = get_account_id();
    if (!$account_id) {
        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'];
    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;
    }
    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 ($data['compatibility']['project'] !== PLATFORM_NAME) {
            notice(t('The data provided is not compatible with this project.'));
            return;
        }
    }
    if ($v2 > $v1) {
        $t = sprintf(t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1);
        notice($t);
    }
    // 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) {
        if ($r[0]['channel_guid'] === $channel['channel_guid'] || $r[0]['channel_hash'] === $channel['channel_hash']) {
            logger('mod_import: duplicate channel. ', print_r($channel, true));
            notice(t('Cannot create a duplicate channel identifier on this system. Import failed.') . EOL);
            return;
        } else {
            // try at most ten times to generate a unique address.
            $x = 0;
            $found_unique = false;
            do {
                $tmp = $channel['channel_address'] . mt_rand(1000, 9999);
                $r = q("select * from channel where channel_address = '%s' limit 1", dbesc($tmp));
                if (!$r) {
                    $channel['channel_address'] = $tmp;
                    $found_unique = true;
                    break;
                }
                $x++;
            } while ($x < 10);
            if (!$found_unique) {
                logger('mod_import: duplicate channel. randomisation failed.', print_r($channel, true));
                notice(t('Unable to create a unique channel address. 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)>0 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 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 ) 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'", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc($photos[3]), dbesc($photodate), dbesc($xchan['xchan_hash']));
        }
    }
    // FIXME - ensure we have an xchan if somebody is trying to pull a fast one
    $friends = 0;
    $feeds = 0;
    // import contacts
    $abooks = $data['abook'];
    if ($abooks) {
        foreach ($abooks as $abook) {
            if ($max_friends !== false && $friends > $max_friends) {
                continue;
            }
            if ($max_feeds !== false && $abook['abook_flags'] & ABOOK_FLAG_FEED && $feeds > $max_feeds) {
                continue;
            }
            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)) . "')");
            $friends++;
            if ($abook['abook_flags'] & ABOOK_FLAG_FEED) {
                $feeds++;
            }
        }
    }
    $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 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)) . "')");
        }
    }
    $saved_notification_flags = notifications_off($channel['channel_id']);
    if ($import_posts && array_key_exists('item', $data) && $data['item']) {
        foreach ($data['item'] as $i) {
            $item = get_item_elements($i);
            $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", dbesc($item['mid']), intval($channel['channel_id']));
            if ($r) {
                if ($item['edited'] > $r[0]['edited']) {
                    $item['id'] = $r[0]['id'];
                    $item['uid'] = $channel['channel_id'];
                    item_store_update($item);
                    continue;
                }
            } else {
                $item['aid'] = $channel['channel_account_id'];
                $item['uid'] = $channel['channel_id'];
                $item_result = item_store($item);
            }
        }
    }
    notifications_on($channel['channel_id'], $saved_notification_flags);
    if (array_key_exists('item_id', $data) && $data['item_id']) {
        foreach ($data['item_id'] as $i) {
            $r = q("select id from item where mid = '%s' and uid = %d limit 1", dbesc($i['mid']), intval($channel['channel_id']));
            if (!$r) {
                continue;
            }
            $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", dbesc($i['service']), dbesc($i['sid']), intval($r[0]['id']), intval($channel['channel_id']));
            if (!$z) {
                q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", intval($r[0]['id']), intval($channel['channel_id']), dbesc($i['sid']), dbesc($i['service']));
            }
        }
    }
    // 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.
    proc_run('php', 'include/notifier.php', 'location', $channel['channel_id']);
    // This will indirectly perform a refresh_all *and* update the directory
    proc_run('php', 'include/directory.php', $channel['channel_id']);
    notice(t('Import completed.') . EOL);
    change_channel($channel['channel_id']);
    goaway(z_root() . '/network');
}
Example #15
0
 function loginUser($uid)
 {
     logger("RedOAuth1::loginUser {$uid}");
     $a = get_app();
     $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1", intval($uid));
     if (count($r)) {
         $record = $r[0];
     } else {
         logger('FKOAuth1::loginUser failure: ' . print_r($_SERVER, true), LOGGER_DEBUG);
         header('HTTP/1.0 401 Unauthorized');
         die('This api requires login');
     }
     $_SESSION['uid'] = $record['channel_id'];
     $_SESSION['theme'] = $record['channel_theme'];
     $_SESSION['account_id'] = $record['channel_account_id'];
     $_SESSION['mobile_theme'] = get_pconfig($record['channel_id'], 'system', 'mobile_theme');
     $_SESSION['authenticated'] = 1;
     $_SESSION['my_url'] = $a->get_baseurl() . '/channel/' . $record['channel_address'];
     $_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
     $_SESSION['allow_api'] = true;
     $x = q("select * from account where account_id = %d limit 1", intval($record['channel_account_id']));
     if ($x) {
         $a->account = $x[0];
     }
     change_channel($record['channel_id']);
     $a->channel = $record;
     if (strlen($a->channel['channel_timezone'])) {
         date_default_timezone_set($a->channel['channel_timezone']);
         //			$a->timezone = $a->user['timezone'];
     }
     //		$r = q("SELECT * FROM `contact` WHERE `uid` = %s AND `self` = 1 LIMIT 1",
     //			intval($_SESSION['uid']));
     //		if(count($r)) {
     //			$a->contact = $r[0];
     //			$a->cid = $r[0]['id'];
     //			$_SESSION['cid'] = $a->cid;
     //		}
     //		q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d LIMIT 1",
     //			dbesc(datetime_convert()),
     //			intval($_SESSION['uid'])
     //		);
     //
     //		call_hooks('logged_in', $a->user);
 }
Example #16
0
/**
 * remote post
 * 
 * https://yoursite/rpost?f=&title=&body=&remote_return=
 *
 * This can be called via either GET or POST, use POST for long body content as suhosin often limits GET parameter length
 *
 * f= placeholder, often required
 * title= Title of post
 * body= Body of post
 * url= URL which will be parsed and the results appended to the body
 * source= Source application
 * remote_return= absolute URL to return after posting is finished
 * type= choices are 'html' or 'bbcode', default is 'bbcode'
 *
 */
function rpost_content(&$a)
{
    $o = '';
    if (!local_channel()) {
        if (remote_channel()) {
            // redirect to your own site.
            // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated
            // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin
            // blocks them.
            $url = get_rpost_path($a->get_observer());
            // make sure we're not looping to our own hub
            if ($url && !stristr($url, $a->get_hostname())) {
                foreach ($_REQUEST as $key => $arg) {
                    $url .= '&' . $key . '=' . $arg;
                }
                goaway($url);
            }
        }
        // The login procedure is going to bugger our $_REQUEST variables
        // so save them in the session.
        if (array_key_exists('body', $_REQUEST)) {
            $_SESSION['rpost'] = $_REQUEST;
        }
        return login();
    }
    // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables
    if (!array_key_exists('body', $_REQUEST) && array_key_exists('rpost', $_SESSION)) {
        $_REQUEST = $_SESSION['rpost'];
        unset($_SESSION['rpost']);
    }
    if (array_key_exists('channel', $_REQUEST)) {
        $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", intval(get_account_id()), dbesc($_REQUEST['channel']));
        if ($r) {
            require_once 'include/security.php';
            $change = change_channel($r[0]['channel_id']);
        }
    }
    if ($_REQUEST['remote_return']) {
        $_SESSION['remote_return'] = $_REQUEST['remote_return'];
    }
    if (argc() > 1 && argv(1) === 'return') {
        if ($_SESSION['remote_return']) {
            goaway($_SESSION['remote_return']);
        }
        goaway(z_root() . '/network');
    }
    $plaintext = true;
    //	if(feature_enabled(local_channel(),'richtext'))
    //		$plaintext = false;
    if (array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') {
        require_once 'include/html2bbcode.php';
        $_REQUEST['body'] = html2bbcode($_REQUEST['body']);
    }
    $channel = $a->get_channel();
    $channel_acl = array('allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid']);
    if ($_REQUEST['url']) {
        $x = z_fetch_url(z_root() . '/parse_url?f=&url=' . urlencode($_REQUEST['url']));
        if ($x['success']) {
            $_REQUEST['body'] = $_REQUEST['body'] . $x['body'];
        }
    }
    $x = array('is_owner' => true, 'allow_location' => intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location')) ? '1' : '', 'default_location' => $channel['channel_location'], 'nickname' => $channel['channel_address'], 'lockstate' => $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid'] ? 'lock' : 'unlock', 'acl' => populate_acl($channel_acl), 'bang' => '', 'visitor' => true, 'profile_uid' => local_channel(), 'title' => $_REQUEST['title'], 'body' => $_REQUEST['body'], 'attachment' => $_REQUEST['attachment'], 'source' => x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '', 'return_path' => 'rpost/return');
    $editor = status_editor($a, $x);
    $o .= replace_macros(get_markup_template('edpost_head.tpl'), array('$title' => t('Edit post'), '$editor' => $editor));
    return $o;
}
Example #17
0
File: import.php Project: 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');
}
Example #18
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);
 }
Example #19
0
/**
 * @brief HTTP POST entry point for Zot.
 *
 * Most access to this endpoint is via the post method.
 * Here we will pick out the magic auth params which arrive as a get request,
 * and the only communications to arrive this way.
 *
 * Magic Auth
 * ==========
 *
 * So-called "magic auth" takes place by a special exchange. On the site where the "channel to be authenticated" lives (e.g. $mysite), 
 * a redirection is made via $mysite/magic to the zot endpoint of the remote site ($remotesite) with special GET parameters.
 *
 * The endpoint is typically  https://$remotesite/post - or whatever was specified as the callback url in prior communications
 * (we will bootstrap an address and fetch a zot info packet if possible where no prior communications exist)
 *
 * Five GET parameters are supplied:
 * * auth => the urlencoded webbie (channel@host.domain) of the channel requesting access
 * * dest => the desired destination URL (urlencoded)
 * * sec  => a random string which is also stored on $mysite for use during the verification phase. 
 * * version => the zot revision
 * * delegate => optional urlencoded webbie of a local channel to invoke delegation rights for
 *
 * When this packet is received, an "auth-check" zot message is sent to $mysite.
 * (e.g. if $_GET['auth'] is foobar@podunk.edu, a zot packet is sent to the podunk.edu zot endpoint, which is typically /post)
 * If no information has been recorded about the requesting identity a zot information packet will be retrieved before
 * continuing.
 *
 * The sender of this packet is an arbitrary/random site channel. The recipients will be a single recipient corresponding
 * to the guid and guid_sig we have associated with the requesting auth identity
 *
 * \code{.json}
 * {
 *   "type":"auth_check",
 *   "sender":{
 *     "guid":"kgVFf_...",
 *     "guid_sig":"PT9-TApz...",
 *     "url":"http:\/\/podunk.edu",
 *     "url_sig":"T8Bp7j..."
 *   },
 *   "recipients":{
 *     {
 *       "guid":"ZHSqb...",
 *       "guid_sig":"JsAAXi..."
 *     }
 *   }
 *   "callback":"\/post",
 *   "version":1,
 *   "secret":"1eaa661",
 *   "secret_sig":"eKV968b1..."
 * }
 * \endcode
 *
 * auth_check messages MUST use encapsulated encryption. This message is sent to the origination site, which checks the 'secret' to see 
 * if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the 
 * destination channel's private key and base64url encoded. If everything checks out, a json packet is returned:
 *
 * \code{.json}
 * {
 *   "success":1,
 *   "confirm":"q0Ysovd1u...",
 *   "service_class":(optional)
 *   "level":(optional)
 * }
 * \endcode
 *
 * 'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the
 * base64url encoded whirlpool hash of the requestor's guid and guid_sig; signed with the source channel private key. 
 * This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful 
 * verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. 
 * Service_class can be used by cooperating sites to provide different access rights based on account rights and subscription plans. It is 
 * a string whose contents are not defined by protocol. Example: "basic" or "gold".
 *
 * @param[in,out] App &$a
 */
function post_init(&$a)
{
    if (array_key_exists('auth', $_REQUEST)) {
        $ret = array('success' => false, 'message' => '');
        logger('mod_zot: auth request received.');
        $address = $_REQUEST['auth'];
        $desturl = $_REQUEST['dest'];
        $sec = $_REQUEST['sec'];
        $version = $_REQUEST['version'];
        $delegate = $_REQUEST['delegate'];
        $test = x($_REQUEST, 'test') ? intval($_REQUEST['test']) : 0;
        // They are authenticating ultimately to the site and not to a particular channel.
        // Any channel will do, providing it's currently active. We just need to have an
        // identity to attach to the packet we send back. So find one.
        $c = q("select * from channel where channel_removed = 0 limit 1");
        if (!$c) {
            // nobody here
            logger('mod_zot: auth: unable to find a response channel');
            if ($test) {
                $ret['message'] .= 'no local channels found.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        // Try and find a hubloc for the person attempting to auth
        $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc", dbesc($address));
        if (!$x) {
            // finger them if they can't be found.
            $ret = zot_finger($address, null);
            if ($ret['success']) {
                $j = json_decode($ret['body'], true);
                if ($j) {
                    import_xchan($j);
                }
                $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc", dbesc($address));
            }
        }
        if (!$x) {
            logger('mod_zot: auth: unable to finger ' . $address);
            if ($test) {
                $ret['message'] .= 'no hubloc found for ' . $address . ' and probing failed.' . EOL;
                json_return_and_die($ret);
            }
            goaway($desturl);
        }
        foreach ($x as $xx) {
            logger('mod_zot: auth request received from ' . $xx['hubloc_addr']);
            // check credentials and access
            // If they are already authenticated and haven't changed credentials,
            // we can save an expensive network round trip and improve performance.
            $remote = remote_channel();
            $result = null;
            $remote_service_class = '';
            $remote_level = 0;
            $remote_hub = $xx['hubloc_url'];
            $DNT = 0;
            // Also check that they are coming from the same site as they authenticated with originally.
            $already_authed = $remote && $xx['hubloc_hash'] == $remote && $xx['hubloc_url'] === $_SESSION['remote_hub'] ? true : false;
            if ($delegate && $delegate !== $_SESSION['delegate_channel']) {
                $already_authed = false;
            }
            $j = array();
            if (!$already_authed) {
                // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the site private key
                // The actual channel sending the packet ($c[0]) is not important, but this provides a generic zot packet with a sender
                // which can be verified
                $p = zot_build_packet($c[0], $type = 'auth_check', array(array('guid' => $xx['hubloc_guid'], 'guid_sig' => $xx['hubloc_guid_sig'])), $xx['hubloc_sitekey'], $sec);
                if ($test) {
                    $ret['message'] .= 'auth check packet created using sitekey ' . $xx['hubloc_sitekey'] . EOL;
                    $ret['message'] .= 'packet contents: ' . $p . EOL;
                }
                $result = zot_zot($xx['hubloc_callback'], $p);
                if (!$result['success']) {
                    logger('mod_zot: auth_check callback failed.');
                    if ($test) {
                        $ret['message'] .= 'auth check request to your site returned .' . print_r($result, true) . EOL;
                        continue;
                    }
                    continue;
                }
                $j = json_decode($result['body'], true);
                if (!$j) {
                    logger('mod_zot: auth_check json data malformed.');
                    if ($test) {
                        $ret['message'] .= 'json malformed: ' . $result['body'] . EOL;
                        continue;
                    }
                }
            }
            if ($test) {
                $ret['message'] .= 'auth check request returned .' . print_r($j, true) . EOL;
            }
            if ($already_authed || $j['success']) {
                if ($j['success']) {
                    // legit response, but we do need to check that this wasn't answered by a man-in-middle
                    if (!rsa_verify($sec . $xx['xchan_hash'], base64url_decode($j['confirm']), $xx['xchan_pubkey'])) {
                        logger('mod_zot: auth: final confirmation failed.');
                        if ($test) {
                            $ret['message'] .= 'final confirmation failed. ' . $sec . print_r($j, true) . print_r($xx, true);
                            continue;
                        }
                        continue;
                    }
                    if (array_key_exists('service_class', $j)) {
                        $remote_service_class = $j['service_class'];
                    }
                    if (array_key_exists('level', $j)) {
                        $remote_level = $j['level'];
                    }
                    if (array_key_exists('DNT', $j)) {
                        $DNT = $j['DNT'];
                    }
                }
                // everything is good... maybe
                if (local_channel()) {
                    // tell them to logout if they're logged in locally as anything but the target remote account
                    // in which case just shut up because they don't need to be doing this at all.
                    if ($a->channel['channel_hash'] != $xx['xchan_hash']) {
                        logger('mod_zot: auth: already authenticated locally as somebody else.');
                        notice(t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL);
                        if ($test) {
                            $ret['message'] .= 'already logged in locally with a conflicting identity.' . EOL;
                            continue;
                        }
                    }
                    continue;
                }
                // log them in
                if ($test) {
                    $ret['success'] = true;
                    $ret['message'] .= 'Authentication Success!' . EOL;
                    json_return_and_die($ret);
                }
                $delegation_success = false;
                if ($delegate) {
                    $r = q("select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", dbesc($delegate));
                    if ($r && intval($r[0]['channel_id'])) {
                        $allowed = perm_is_allowed($r[0]['channel_id'], $xx['xchan_hash'], 'delegate');
                        if ($allowed) {
                            $_SESSION['delegate_channel'] = $r[0]['channel_id'];
                            $_SESSION['delegate'] = $xx['xchan_hash'];
                            $_SESSION['account_id'] = intval($r[0]['channel_account_id']);
                            require_once 'include/security.php';
                            change_channel($r[0]['channel_id']);
                            $delegation_success = true;
                        }
                    }
                }
                $_SESSION['authenticated'] = 1;
                if (!$delegation_success) {
                    $_SESSION['visitor_id'] = $xx['xchan_hash'];
                    $_SESSION['my_url'] = $xx['xchan_url'];
                    $_SESSION['my_address'] = $address;
                    $_SESSION['remote_service_class'] = $remote_service_class;
                    $_SESSION['remote_level'] = $remote_level;
                    $_SESSION['remote_hub'] = $remote_hub;
                    $_SESSION['DNT'] = $DNT;
                }
                $arr = array('xchan' => $xx, 'url' => $desturl, 'session' => $_SESSION);
                call_hooks('magic_auth_success', $arr);
                $a->set_observer($xx);
                require_once 'include/security.php';
                $a->set_groups(init_groups_visitor($_SESSION['visitor_id']));
                info(sprintf(t('Welcome %s. Remote authentication successful.'), $xx['xchan_name']));
                logger('mod_zot: auth success from ' . $xx['xchan_addr']);
            } else {
                if ($test) {
                    $ret['message'] .= 'auth failure. ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
                    continue;
                }
                logger('mod_zot: magic-auth failure - not authenticated: ' . $xx['xchan_addr']);
            }
            if ($test) {
                $ret['message'] .= 'auth failure fallthrough ' . print_r($_REQUEST, true) . print_r($j, true) . EOL;
                continue;
            }
        }
        /**
         * @FIXME we really want to save the return_url in the session before we
         * visit rmagic. This does however prevent a recursion if you visit
         * rmagic directly, as it would otherwise send you back here again.
         * But z_root() probably isn't where you really want to go.
         */
        if (strstr($desturl, z_root() . '/rmagic')) {
            goaway(z_root());
        }
        if ($test) {
            json_return_and_die($ret);
        }
        goaway($desturl);
    }
}