Hubzilla core code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

155 lines
4.2 KiB

  1. <?php
  2. namespace Zotlabs\Zot;
  3. use Zotlabs\Web\HTTPSig;
  4. /**
  5. * @brief Finger
  6. *
  7. */
  8. class Finger {
  9. static private $token;
  10. /**
  11. * @brief Look up information about channel.
  12. *
  13. * @param string $webbie
  14. * does not have to be host qualified e.g. 'foo' is treated as 'foo\@thishub'
  15. * @param array $channel
  16. * (optional), if supplied permissions will be enumerated specifically for $channel
  17. * @param boolean $autofallback
  18. * fallback/failover to http if https connection cannot be established. Default is true.
  19. *
  20. * @return zotinfo array (with 'success' => true) or array('success' => false);
  21. */
  22. static public function run($webbie, $channel = null, $autofallback = true) {
  23. $ret = array('success' => false);
  24. self::$token = random_string();
  25. if (strpos($webbie, '@') === false) {
  26. $address = $webbie;
  27. $host = \App::get_hostname();
  28. } else {
  29. $address = substr($webbie,0,strpos($webbie,'@'));
  30. $host = substr($webbie,strpos($webbie,'@')+1);
  31. if(strpos($host,'/'))
  32. $host = substr($host,0,strpos($host,'/'));
  33. }
  34. $xchan_addr = $address . '@' . $host;
  35. if ((! $address) || (! $xchan_addr)) {
  36. logger('zot_finger: no address :' . $webbie);
  37. return $ret;
  38. }
  39. logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG);
  40. // potential issue here; the xchan_addr points to the primary hub.
  41. // The webbie we were called with may not, so it might not be found
  42. // unless we query for hubloc_addr instead of xchan_addr
  43. $r = q("select xchan.*, hubloc.* from xchan
  44. left join hubloc on xchan_hash = hubloc_hash
  45. where xchan_addr = '%s' and hubloc_primary = 1 and hubloc_deleted = 0 and hubloc_network = 'zot' limit 1",
  46. dbesc($xchan_addr)
  47. );
  48. if($r) {
  49. $url = $r[0]['hubloc_url'];
  50. if($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') {
  51. logger('zot_finger: alternate network: ' . $webbie);
  52. logger('url: ' . $url . ', net: ' . var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG);
  53. return $ret;
  54. }
  55. } else {
  56. $url = 'https://' . $host;
  57. }
  58. $m = parse_url($url);
  59. if($m) {
  60. $parsed_host = strtolower($m['host']);
  61. }
  62. $rhs = '/.well-known/zot-info';
  63. $https = ((strpos($url,'https://') === 0) ? true : false);
  64. logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG);
  65. if ($channel) {
  66. $postvars = array(
  67. 'address' => $address,
  68. 'target' => $channel['channel_guid'],
  69. 'target_sig' => $channel['channel_guid_sig'],
  70. 'key' => $channel['channel_pubkey'],
  71. 'token' => self::$token
  72. );
  73. $headers = [];
  74. $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
  75. $headers['X-Zot-Nonce'] = random_string();
  76. $headers['Host'] = $parsed_host;
  77. $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],'acct:' . channel_reddress($channel));
  78. $retries = 0;
  79. $result = z_post_url($url . $rhs,$postvars,$retries, [ 'headers' => $xhead ]);
  80. if ((! $result['success']) && ($autofallback)) {
  81. if ($https) {
  82. logger('zot_finger: https failed. falling back to http');
  83. $result = z_post_url('http://' . $host . $rhs,$postvars, $retries, [ 'headers' => $xhead ]);
  84. }
  85. }
  86. }
  87. else {
  88. $rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token;
  89. $result = z_fetch_url($url . $rhs);
  90. if((! $result['success']) && ($autofallback)) {
  91. if($https) {
  92. logger('zot_finger: https failed. falling back to http');
  93. $result = z_fetch_url('http://' . $host . $rhs);
  94. }
  95. }
  96. }
  97. if(! $result['success']) {
  98. logger('zot_finger: no results');
  99. return $ret;
  100. }
  101. $x = json_decode($result['body'], true);
  102. $verify = HTTPSig::verify($result,(($x) ? $x['key'] : ''));
  103. if($x && (! $verify['header_valid'])) {
  104. $signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
  105. if($signed_token) {
  106. $valid = rsa_verify('token.' . self::$token, base64url_decode($signed_token), $x['key']);
  107. if(! $valid) {
  108. logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR);
  109. return $ret;
  110. }
  111. }
  112. else {
  113. logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
  114. return $ret;
  115. }
  116. }
  117. return $x;
  118. }
  119. }