diff options
Diffstat (limited to 'Zotlabs/Zot6/Finger.php')
-rw-r--r-- | Zotlabs/Zot6/Finger.php | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/Zotlabs/Zot6/Finger.php b/Zotlabs/Zot6/Finger.php new file mode 100644 index 000000000..f1fe41352 --- /dev/null +++ b/Zotlabs/Zot6/Finger.php @@ -0,0 +1,146 @@ +<?php + +namespace Zotlabs\Zot6; + +/** + * @brief Finger + * + */ +class Finger { + + static private $token; + + /** + * @brief Look up information about channel. + * + * @param string $webbie + * does not have to be host qualified e.g. 'foo' is treated as 'foo\@thishub' + * @param array $channel + * (optional), if supplied permissions will be enumerated specifically for $channel + * @param boolean $autofallback + * fallback/failover to http if https connection cannot be established. Default is true. + * + * @return zotinfo array (with 'success' => true) or array('success' => false); + */ + + static public function run($webbie, $channel = null, $autofallback = true) { + + $ret = array('success' => false); + + self::$token = random_string(); + + if (strpos($webbie, '@') === false) { + $address = $webbie; + $host = \App::get_hostname(); + } else { + $address = substr($webbie,0,strpos($webbie,'@')); + $host = substr($webbie,strpos($webbie,'@')+1); + if(strpos($host,'/')) + $host = substr($host,0,strpos($host,'/')); + } + + $xchan_addr = $address . '@' . $host; + + if ((! $address) || (! $xchan_addr)) { + logger('zot_finger: no address :' . $webbie); + + return $ret; + } + + logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG); + + // potential issue here; the xchan_addr points to the primary hub. + // The webbie we were called with may not, so it might not be found + // unless we query for hubloc_addr instead of xchan_addr + + $r = q("select xchan.*, hubloc.* from xchan + left join hubloc on xchan_hash = hubloc_hash + where xchan_addr = '%s' and hubloc_primary = 1 limit 1", + dbesc($xchan_addr) + ); + + if($r) { + $url = $r[0]['hubloc_url']; + + if($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') { + logger('zot_finger: alternate network: ' . $webbie); + logger('url: ' . $url . ', net: ' . var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG); + return $ret; + } + } else { + $url = 'https://' . $host; + } + + $rhs = '/.well-known/zot-info'; + $https = ((strpos($url,'https://') === 0) ? true : false); + + logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG); + + if ($channel) { + $postvars = array( + 'address' => $address, + 'target' => $channel['channel_guid'], + 'target_sig' => $channel['channel_guid_sig'], + 'key' => $channel['channel_pubkey'], + 'token' => self::$token + ); + + $headers = []; + $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname(); + $headers['X-Zot-Nonce'] = random_string(); + $xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'], + 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false); + + $retries = 0; + + $result = z_post_url($url . $rhs,$postvars,$retries, [ 'headers' => $xhead ]); + + if ((! $result['success']) && ($autofallback)) { + if ($https) { + logger('zot_finger: https failed. falling back to http'); + $result = z_post_url('http://' . $host . $rhs,$postvars, $retries, [ 'headers' => $xhead ]); + } + } + } + else { + $rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token; + + $result = z_fetch_url($url . $rhs); + if((! $result['success']) && ($autofallback)) { + if($https) { + logger('zot_finger: https failed. falling back to http'); + $result = z_fetch_url('http://' . $host . $rhs); + } + } + } + + if(! $result['success']) { + logger('zot_finger: no results'); + + return $ret; + } + + $x = json_decode($result['body'], true); + + $verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : '')); + + if($x && (! $verify['header_valid'])) { + $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null); + if($signed_token) { + $valid = zot_verify('token.' . self::$token, base64url_decode($signed_token), $x['key']); + if(! $valid) { + logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR); + + return $ret; + } + } + else { + logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING); + return $ret; + } + } + + return $x; + } + +} |