diff options
-rw-r--r-- | include/network.php | 4 | ||||
-rw-r--r-- | include/zot.php | 288 | ||||
-rw-r--r-- | mod/webfinger.php | 2 | ||||
-rw-r--r-- | mod/wfinger.php | 15 | ||||
-rw-r--r-- | mod/zfinger.php | 281 |
5 files changed, 299 insertions, 291 deletions
diff --git a/include/network.php b/include/network.php index d3320f3ee..48371c5e2 100644 --- a/include/network.php +++ b/include/network.php @@ -1282,7 +1282,7 @@ LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+ } -function webfinger_rfc7033($webbie) { +function webfinger_rfc7033($webbie,$zot = false) { if(! strpos($webbie,'@')) @@ -1292,7 +1292,7 @@ function webfinger_rfc7033($webbie) { $resource = 'acct:' . $webbie; - $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?resource=' . $resource); + $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : '')); if($s['success']) $j = json_decode($s['body'],true); diff --git a/include/zot.php b/include/zot.php index 7e45b29c5..ebdcb4cfb 100644 --- a/include/zot.php +++ b/include/zot.php @@ -3404,3 +3404,291 @@ function zot_process_message_request($data) { return $ret; } + + +function zotinfo($arr) { + + $ret = array('success' => false); + + $zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : ''); + $zguid = ((x($arr,'guid')) ? $arr['guid'] : ''); + $zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : ''); + $zaddr = ((x($arr,'address')) ? $arr['address'] : ''); + $ztarget = ((x($arr,'target')) ? $arr['target'] : ''); + $zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : ''); + $zkey = ((x($arr,'key')) ? $arr['key'] : ''); + $mindate = ((x($arr,'mindate')) ? $arr['mindate'] : ''); + $feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0); + + if($ztarget) { + if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) { + logger('zfinger: invalid target signature'); + $ret['message'] = t("invalid target signature"); + return($ret); + } + } + + $r = null; + + if(strlen($zhash)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_hash = '%s' limit 1", + dbesc($zhash) + ); + } + elseif(strlen($zguid) && strlen($zguid_sig)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($zguid), + dbesc($zguid_sig) + ); + } + elseif(strlen($zaddr)) { + if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", + dbesc($zaddr), + dbesc($zaddr) + ); + } + + else { + + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ + + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_system = 1 order by channel_id limit 1"); + if(! $r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_removed = 0 order by channel_id limit 1"); + } + } + } + else { + $ret['message'] = 'Invalid request'; + return($ret); + } + + if(! $r) { + $ret['message'] = 'Item not found.'; + return($ret); + } + + $e = $r[0]; + + $id = $e['channel_id']; + + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (intval($e['xchan_deleted']) ? true : false); + + if($deleted || $censored || $sys_channel) + $searchable = false; + + $public_forum = false; + + $role = get_pconfig($e['channel_id'],'system','permissions_role'); + if($role === 'forum' || $role === 'repository') { + $public_forum = true; + } + else { + // check if it has characteristics of a public forum based on custom permissions. + $t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", + intval($e['channel_id']) + ); + if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM)))) + $public_forum = true; + } + + + // This is for birthdays and keywords, but must check access permissions + $p = q("select * from profile where uid = %d and is_default = 1", + intval($e['channel_id']) + ); + + $profile = array(); + + if($p) { + + if(! intval($p[0]['publish'])) + $searchable = false; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + $profile['next_birthday'] = $bd; + + if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + $profile['age'] = $age; + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if($p[0]['keywords']) { + $tags = array(); + $k = explode(' ',$p[0]['keywords']); + if($k) { + foreach($k as $kk) { + if(trim($kk," \t\n\r\0\x0B,")) { + $tags[] = trim($kk," \t\n\r\0\x0B,"); + } + } + } + if($tags) + $profile['keywords'] = $tags; + } + } + + $ret['success'] = true; + + // Communication details + + $ret['guid'] = $e['xchan_guid']; + $ret['guid_sig'] = $e['xchan_guid_sig']; + $ret['key'] = $e['xchan_pubkey']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['address'] = $e['xchan_addr']; + $ret['photo_mimetype'] = $e['xchan_photo_mimetype']; + $ret['photo'] = $e['xchan_photo_l']; + $ret['photo_updated'] = $e['xchan_photo_date']; + $ret['url'] = $e['xchan_url']; + $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); + $ret['target'] = $ztarget; + $ret['target_sig'] = $zsig; + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + $ret['public_forum'] = $public_forum; + if($deleted) + $ret['deleted'] = $deleted; + + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. + + if($special_channel) + $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; + + // This is a template for our follow url, %s will be replaced with a webbie + + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + + $ztarget_hash = (($ztarget && $zsig) + ? make_xchan_hash($ztarget,$zsig) + : '' ); + + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + + if($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if($b) + $permissions['connected'] = true; + } + + $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); + + if($permissions['view_profile']) + $ret['profile'] = $profile; + + // array of (verified) hubs this channel uses + + $x = zot_encode_locations($e); + if($x) + $ret['locations'] = $x; + + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + + $dirmode = get_config('system','directory_mode'); + if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + $ret['site']['directory_mode'] = 'normal'; + + if($dirmode == DIRECTORY_MODE_PRIMARY) + $ret['site']['directory_mode'] = 'primary'; + elseif($dirmode == DIRECTORY_MODE_SECONDARY) + $ret['site']['directory_mode'] = 'secondary'; + elseif($dirmode == DIRECTORY_MODE_STANDALONE) + $ret['site']['directory_mode'] = 'standalone'; + if($dirmode != DIRECTORY_MODE_NORMAL) + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + + + // hide detailed site information if you're off the grid + + if($dirmode != DIRECTORY_MODE_STANDALONE) { + + $register_policy = intval(get_config('system','register_policy')); + + if($register_policy == REGISTER_CLOSED) + $ret['site']['register_policy'] = 'closed'; + if($register_policy == REGISTER_APPROVE) + $ret['site']['register_policy'] = 'approve'; + if($register_policy == REGISTER_OPEN) + $ret['site']['register_policy'] = 'open'; + + + $access_policy = intval(get_config('system','access_policy')); + + if($access_policy == ACCESS_PRIVATE) + $ret['site']['access_policy'] = 'private'; + if($access_policy == ACCESS_PAID) + $ret['site']['access_policy'] = 'paid'; + if($access_policy == ACCESS_FREE) + $ret['site']['access_policy'] = 'free'; + if($access_policy == ACCESS_TIERED) + $ret['site']['access_policy'] = 'tiered'; + + $ret['site']['accounts'] = account_total(); + + require_once('include/identity.php'); + $ret['site']['channels'] = channel_total(); + + + $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; + + $ret['site']['admin'] = get_config('system','admin_email'); + + $a = get_app(); + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if($r) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + $ret['site']['realm'] = get_directory_realm(); + + } + call_hooks('zot_finger',$ret); + return($ret); +}
\ No newline at end of file diff --git a/mod/webfinger.php b/mod/webfinger.php index a646961a8..74bfc3ce5 100644 --- a/mod/webfinger.php +++ b/mod/webfinger.php @@ -15,7 +15,7 @@ function webfinger_content(&$a) { if(x($_GET,'addr')) { $addr = trim($_GET['addr']); if(strpos($addr,'@') !== false) { - $res = webfinger_rfc7033($addr); + $res = webfinger_rfc7033($addr,true); if(! $res) $res = old_webfinger($addr); } diff --git a/mod/wfinger.php b/mod/wfinger.php index 7b9eaa461..8b9abe4af 100644 --- a/mod/wfinger.php +++ b/mod/wfinger.php @@ -1,5 +1,7 @@ <?php +require_once('include/zot.php'); + function wfinger_init(&$a) { $result = array(); @@ -11,14 +13,13 @@ function wfinger_init(&$a) { elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) $scheme = 'https'; - // Don't complain to me - I'm just implementing the spec. + $zot = intval($_REQUEST['zot']); - if($scheme !== 'https') { + if(($scheme !== 'https') && (! $zot)) { header($_SERVER["SERVER_PROTOCOL"] . ' ' . 500 . ' ' . 'Webfinger requires HTTPS'); killme(); } - $zot = intval($_REQUEST['zot']); $resource = $_REQUEST['resource']; logger('webfinger: ' . $resource,LOGGER_DEBUG); @@ -48,7 +49,6 @@ function wfinger_init(&$a) { } - header('Access-Control-Allow-Origin: *'); header('Content-type: application/jrd+json'); @@ -107,11 +107,8 @@ function wfinger_init(&$a) { ); if($zot) { - // @FIXME do a lookup straightaway and return the zot-info packet - - $_REQUEST['address'] = $r[0]['xchan_address']; - - + // get a zotinfo packet and return it with webfinger + $result['zot'] = zotinfo(array('address' => $r[0]['xchan_addr'])); } } else { diff --git a/mod/zfinger.php b/mod/zfinger.php index 4f2b1fca7..fb3333280 100644 --- a/mod/zfinger.php +++ b/mod/zfinger.php @@ -5,286 +5,9 @@ function zfinger_init(&$a) { require_once('include/zot.php'); require_once('include/crypto.php'); - $ret = array('success' => false); - $zhash = ((x($_REQUEST,'guid_hash')) ? $_REQUEST['guid_hash'] : ''); - $zguid = ((x($_REQUEST,'guid')) ? $_REQUEST['guid'] : ''); - $zguid_sig = ((x($_REQUEST,'guid_sig')) ? $_REQUEST['guid_sig'] : ''); - $zaddr = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); - $ztarget = ((x($_REQUEST,'target')) ? $_REQUEST['target'] : ''); - $zsig = ((x($_REQUEST,'target_sig')) ? $_REQUEST['target_sig'] : ''); - $zkey = ((x($_REQUEST,'key')) ? $_REQUEST['key'] : ''); - $mindate = ((x($_REQUEST,'mindate')) ? $_REQUEST['mindate'] : ''); - $feed = ((x($_REQUEST,'feed')) ? intval($_REQUEST['feed']) : 0); + $x = zotinfo($_REQUEST); + json_return_and_die($x); - if($ztarget) { - if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) { - logger('zfinger: invalid target signature'); - $ret['message'] = t("invalid target signature"); - json_return_and_die($ret); - } - } - - $r = null; - - if(strlen($zhash)) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where channel_hash = '%s' limit 1", - dbesc($zhash) - ); - } - elseif(strlen($zguid) && strlen($zguid_sig)) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", - dbesc($zguid), - dbesc($zguid_sig) - ); - } - elseif(strlen($zaddr)) { - if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", - dbesc($zaddr), - dbesc($zaddr) - ); - } - - else { - - /** - * The special address '[system]' will return a system channel if one has been defined, - * Or the first valid channel we find if there are no system channels. - * - * This is used by magic-auth if we have no prior communications with this site - and - * returns an identity on this site which we can use to create a valid hub record so that - * we can exchange signed messages. The precise identity is irrelevant. It's the hub - * information that we really need at the other end - and this will return it. - * - */ - - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where channel_system = 1 order by channel_id limit 1"); - if(! $r) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash - where channel_removed = 0 order by channel_id limit 1"); - } - } - } - else { - $ret['message'] = 'Invalid request'; - json_return_and_die($ret); - } - - if(! $r) { - $ret['message'] = 'Item not found.'; - json_return_and_die($ret); - } - - $e = $r[0]; - - $id = $e['channel_id']; - - $sys_channel = (intval($e['channel_system']) ? true : false); - $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); - $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); - $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); - $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); - $deleted = (intval($e['xchan_deleted']) ? true : false); - - if($deleted || $censored || $sys_channel) - $searchable = false; - - $public_forum = false; - - $role = get_pconfig($e['channel_id'],'system','permissions_role'); - if($role === 'forum' || $role === 'repository') { - $public_forum = true; - } - else { - // check if it has characteristics of a public forum based on custom permissions. - $t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", - intval($e['channel_id']) - ); - if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM)))) - $public_forum = true; - } - - - // This is for birthdays and keywords, but must check access permissions - $p = q("select * from profile where uid = %d and is_default = 1", - intval($e['channel_id']) - ); - - $profile = array(); - - if($p) { - - if(! intval($p[0]['publish'])) - $searchable = false; - - $profile['description'] = $p[0]['pdesc']; - $profile['birthday'] = $p[0]['dob']; - if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) - $profile['next_birthday'] = $bd; - - if($age = age($p[0]['dob'],$e['channel_timezone'],'')) - $profile['age'] = $age; - $profile['gender'] = $p[0]['gender']; - $profile['marital'] = $p[0]['marital']; - $profile['sexual'] = $p[0]['sexual']; - $profile['locale'] = $p[0]['locality']; - $profile['region'] = $p[0]['region']; - $profile['postcode'] = $p[0]['postal_code']; - $profile['country'] = $p[0]['country_name']; - $profile['about'] = $p[0]['about']; - $profile['homepage'] = $p[0]['homepage']; - $profile['hometown'] = $p[0]['hometown']; - - if($p[0]['keywords']) { - $tags = array(); - $k = explode(' ',$p[0]['keywords']); - if($k) { - foreach($k as $kk) { - if(trim($kk," \t\n\r\0\x0B,")) { - $tags[] = trim($kk," \t\n\r\0\x0B,"); - } - } - } - if($tags) - $profile['keywords'] = $tags; - } - } - - $ret['success'] = true; - - // Communication details - - $ret['guid'] = $e['xchan_guid']; - $ret['guid_sig'] = $e['xchan_guid_sig']; - $ret['key'] = $e['xchan_pubkey']; - $ret['name'] = $e['xchan_name']; - $ret['name_updated'] = $e['xchan_name_date']; - $ret['address'] = $e['xchan_addr']; - $ret['photo_mimetype'] = $e['xchan_photo_mimetype']; - $ret['photo'] = $e['xchan_photo_l']; - $ret['photo_updated'] = $e['xchan_photo_date']; - $ret['url'] = $e['xchan_url']; - $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); - $ret['target'] = $ztarget; - $ret['target_sig'] = $zsig; - $ret['searchable'] = $searchable; - $ret['adult_content'] = $adult_channel; - $ret['public_forum'] = $public_forum; - if($deleted) - $ret['deleted'] = $deleted; - - // premium or other channel desiring some contact with potential followers before connecting. - // This is a template - %s will be replaced with the follow_url we discover for the return channel. - - if($special_channel) - $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; - - // This is a template for our follow url, %s will be replaced with a webbie - - $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - - $ztarget_hash = (($ztarget && $zsig) - ? make_xchan_hash($ztarget,$zsig) - : '' ); - - $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); - - if($ztarget_hash) { - $permissions['connected'] = false; - $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($ztarget_hash), - intval($e['channel_id']) - ); - if($b) - $permissions['connected'] = true; - } - - $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); - - if($permissions['view_profile']) - $ret['profile'] = $profile; - - // array of (verified) hubs this channel uses - - $x = zot_encode_locations($e); - if($x) - $ret['locations'] = $x; - - $ret['site'] = array(); - $ret['site']['url'] = z_root(); - $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); - - $dirmode = get_config('system','directory_mode'); - if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) - $ret['site']['directory_mode'] = 'normal'; - - if($dirmode == DIRECTORY_MODE_PRIMARY) - $ret['site']['directory_mode'] = 'primary'; - elseif($dirmode == DIRECTORY_MODE_SECONDARY) - $ret['site']['directory_mode'] = 'secondary'; - elseif($dirmode == DIRECTORY_MODE_STANDALONE) - $ret['site']['directory_mode'] = 'standalone'; - if($dirmode != DIRECTORY_MODE_NORMAL) - $ret['site']['directory_url'] = z_root() . '/dirsearch'; - - - // hide detailed site information if you're off the grid - - if($dirmode != DIRECTORY_MODE_STANDALONE) { - - $register_policy = intval(get_config('system','register_policy')); - - if($register_policy == REGISTER_CLOSED) - $ret['site']['register_policy'] = 'closed'; - if($register_policy == REGISTER_APPROVE) - $ret['site']['register_policy'] = 'approve'; - if($register_policy == REGISTER_OPEN) - $ret['site']['register_policy'] = 'open'; - - - $access_policy = intval(get_config('system','access_policy')); - - if($access_policy == ACCESS_PRIVATE) - $ret['site']['access_policy'] = 'private'; - if($access_policy == ACCESS_PAID) - $ret['site']['access_policy'] = 'paid'; - if($access_policy == ACCESS_FREE) - $ret['site']['access_policy'] = 'free'; - if($access_policy == ACCESS_TIERED) - $ret['site']['access_policy'] = 'tiered'; - - $ret['site']['accounts'] = account_total(); - - require_once('include/identity.php'); - $ret['site']['channels'] = channel_total(); - - - $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; - - $ret['site']['admin'] = get_config('system','admin_email'); - - $visible_plugins = array(); - if(is_array($a->plugins) && count($a->plugins)) { - $r = q("select * from addon where hidden = 0"); - if($r) - foreach($r as $rr) - $visible_plugins[] = $rr['name']; - } - - $ret['site']['plugins'] = $visible_plugins; - $ret['site']['sitehash'] = get_config('system','location_hash'); - $ret['site']['sitename'] = get_config('system','sitename'); - $ret['site']['sellpage'] = get_config('system','sellpage'); - $ret['site']['location'] = get_config('system','site_location'); - $ret['site']['realm'] = get_directory_realm(); - - } - call_hooks('zot_finger',$ret); - json_return_and_die($ret); } |