130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Zotlabs\Zot;
 | 
						|
 | 
						|
 | 
						|
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);
 | 
						|
		}
 | 
						|
 | 
						|
		$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
 | 
						|
			);
 | 
						|
 | 
						|
			$result = z_post_url($url . $rhs,$postvars);
 | 
						|
 | 
						|
			if ((! $result['success']) && ($autofallback)) {
 | 
						|
				if ($https) {
 | 
						|
					logger('zot_finger: https failed. falling back to http');
 | 
						|
					$result = z_post_url('http://' . $host . $rhs,$postvars);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} 
 | 
						|
		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);
 | 
						|
		if($x) {
 | 
						|
			$signed_token = ((is_array($x) && array_key_exists('signed_token',$x)) ? $x['signed_token'] : null);
 | 
						|
			if($signed_token) {
 | 
						|
				$valid = rsa_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);
 | 
						|
				// after 2017-01-01 this will be a hard error unless you over-ride it.
 | 
						|
				if((time() > 1483228800) && (! get_config('system','allow_unsigned_zotfinger')))
 | 
						|
					return $ret;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return $x;
 | 
						|
	}
 | 
						|
 | 
						|
} |