From 6f2ba0c6193a229b3f371de2cae7b314927d4cbb Mon Sep 17 00:00:00 2001 From: redmatrix Date: Tue, 22 Mar 2016 19:58:59 -0700 Subject: rewrite the webfinger discovery logic --- include/network.php | 454 ++++++++++++++++++++++++---------------------------- 1 file changed, 210 insertions(+), 244 deletions(-) (limited to 'include/network.php') diff --git a/include/network.php b/include/network.php index 3efc82447..dd0089bf8 100644 --- a/include/network.php +++ b/include/network.php @@ -1061,32 +1061,16 @@ function discover_by_url($url,$arr = null) { } -function convert_salmon_key($key) { - - if(strstr($key,',')) - $rawkey = substr($key,strpos($key,',')+1); - else - $rawkey = substr($key,5); - - $key_info = explode('.',$rawkey); - - $m = base64url_decode($key_info[1]); - $e = base64url_decode($key_info[2]); - - logger('key details: ' . print_r($key_info,true), LOGGER_DEBUG); - $salmon_key = metopem($m,$e); - return $salmon_key; - -} - - function discover_by_webbie($webbie) { require_once('library/HTML5/Parser.php'); - $result = array(); - $network = null; + $result = array(); + + $network = null; + $diaspora = false; - $gnusoc = false; + $gnusoc = false; + $dfrn = false; $has_salmon = false; $salmon_key = false; @@ -1094,7 +1078,6 @@ function discover_by_webbie($webbie) { $diaspora_base = ''; $diaspora_guid = ''; $diaspora_key = ''; - $dfrn = false; $webbie = strtolower($webbie); @@ -1102,6 +1085,10 @@ function discover_by_webbie($webbie) { if($x && array_key_exists('links',$x) && $x['links']) { foreach($x['links'] as $link) { if(array_key_exists('rel',$link)) { + + // If we discover zot - don't search further; grab the info and get out of + // here. + if($link['rel'] == 'http://purl.org/zot/protocol') { logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG); if(array_key_exists('zot',$x) && $x['zot']['success']) @@ -1115,6 +1102,9 @@ function discover_by_webbie($webbie) { } } } + if($link['rel'] == NAMESPACE_DFRN) { + $dfrn = $link['href']; + } if($link['rel'] == 'magic-public-key') { if(substr($link['href'],0,5) === 'data:') { $salmon_key = convert_salmon_key($link['href']); @@ -1131,88 +1121,40 @@ function discover_by_webbie($webbie) { } } - logger('webfing: ' . print_r($x,true), LOGGER_DATA, LOG_INFO); + logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO); $arr = array('address' => $webbie, 'success' => false, 'webfinger' => $x); call_hooks('discover_channel_webfinger', $arr); if($arr['success']) return true; - if($salmon_key && $has_salmon && $atom_feed) { - - $gnusoc = true; - $addr = $x['address']; + $aliases = array(); - $m = parse_url($x['location']); + // Now let's make some decisions on what we may need + // to obtain further info - $k = z_fetch_url($atom_feed); - if($k['success']) - $feed_meta = feed_meta($k['body']); + $probe_atom = false; + $probe_old = false; + $probe_hcard = false; - // stash any discovered pubsubhubbub hubs in case we need to follow them - // this will save an expensive lookup later + $address = ''; + $location = ''; + $nickname = ''; + $fullname = ''; + $avatar = ''; + $pubkey = ''; - if($feed_meta['hubs']) - set_xconfig($addr,'system','push_hubs',$feed_meta['hubs']); + if(array_key_exists('address',$x)) + $address = $x['address']; + if(array_key_exists('location',$x)) + $location = $x['location']; + if(array_key_exists('nickname',$x)) + $nickname = $x['nickname']; - if($feed_meta && $feed_meta['author']) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($addr) - ); - if($r) { - $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", - dbesc(($feed_meta['author']['author_name']) ? $feed_meta['author']['author_name'] : $x['nickname']), - dbesc('gnusoc'), - dbesc(datetime_convert()), - dbesc($addr) - ); - } - else { - - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - dbesc($addr), - dbesc($x['location']), - dbesc($salmon_key), - dbesc($addr), - dbesc($x['location']), - dbesc(($feed_meta['author']['author_name']) ? $feed_meta['author']['author_name'] : $x['nickname']), - dbesc('gnusoc'), - dbescdate(datetime_convert()) - ); - } - - $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($addr) - ); - - if(! $r) { - - $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", - dbesc($x['location']), - dbesc($addr), - dbesc($addr), - dbesc('gnusoc'), - dbesc($m['scheme'] . '://' . $m['host']), - dbesc($m['host']), - dbesc($salmon), - dbescdate(datetime_convert()) - ); - } - $photos = import_xchan_photo($feed_meta['author']['author_photo'],$addr); - $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($addr) - ); - return true; - - } - } - else { + if(! $x) + $probe_old = true; + if($probe_old) { $x = old_webfinger($webbie); if($x) { logger('old_webfinger: ' . print_r($x,true)); @@ -1245,174 +1187,194 @@ function discover_by_webbie($webbie) { $pubkey = $diaspora_key; $diaspora = true; } + if($link['@attributes']['rel'] == 'magic-public-key') { + if(substr($link['@attributes']['href'],0,5) === 'data:') { + $salmon_key = convert_salmon_key($link['@attributes']['href']); + } + } + if($link['@attributes']['rel'] == 'salmon') { + $has_salmon = true; + $salmon = $link['@attributes']['href']; + } + + if($link['@attributes']['rel'] == 'http://schemas.google.com/g/2010#updates-from') { + $atom_feed = $link['@attributes']['href']; + } + if($link['@attributes']['rel'] === 'alias') { + $aliases[] = $link['@attributes']['href']; + } + if($link['@attributes']['rel'] === 'subject') { + $subject = $link['@attributes']['href']; + } } } + } - if($diaspora && $diaspora_base && $diaspora_guid) { - $guid = $diaspora_guid; - $diaspora_base = trim($diaspora_base,'/'); + if($subject || $aliases) { + if(strpos($webbie,'@')) { + $rhs = substr($webbie,strpos($webbie,'@')+1); + } + else { + $m = parse_url($webbie); + if($m) { + $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + } + } - $notify = $diaspora_base . '/receive'; + $v = array('subject' => $subject,'aliases' => $aliases); + $address = find_webfinger_address($v,$rhs); + $location = find_webfinger_location($v,$rhs); + if($address) + $nickname = substr($address,0,strpos($address,'@')); - if(strpos($webbie,'@')) { - $addr = str_replace('acct:', '', $webbie); - $hostname = substr($webbie,strpos($webbie,'@')+1); - } - $network = 'diaspora'; - // until we get a dfrn layer, we'll use diaspora protocols for Friendica, - // but give it a different network so we can go back and fix these when we get proper support. - // It really should be just 'friendica' but we also want to distinguish - // between Friendica sites that we can use D* protocols with and those we can't. - // Some Friendica sites will have Diaspora disabled. - if($dfrn) - $network = 'friendica-over-diaspora'; - if($hcard) { - $vcard = scrape_vcard($hcard); - $vcard['nick'] = substr($webbie,0,strpos($webbie,'@')); - if(! $vcard['fn']) - $vcard['fn'] = $webbie; - } - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($addr) - ); + } - // fix relative urls - if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0)) - $vcard['photo'] = $diaspora_base . '/' . $vcard['photo']; - - /** - * - * Diaspora communications are notoriously unreliable and receiving profile update messages (indeed any messages) - * are pretty much random luck. We'll check the timestamp of the xchan_name_date at a higher level and refresh - * this record once a month; because if you miss a profile update message and they update their profile photo or name - * you're otherwise stuck with stale info until they change their profile again - which could be years from now. - * - */ - - if($r) { - $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", - dbesc($vcard['fn']), - dbesc($network), - dbesc(datetime_convert()), - dbesc($addr) - ); + if($salmon_key && $has_salmon && $atom_feed && (! $dfrn) && (! $diaspora)) { + $gnusoc = true; + $probe_atom = true; + } + + if(! $pubkey) + $pubkey = $salmon_key; + + if(($dfrn || $diaspora) && $hcard) + $probe_hcard = true; + + if(! $fullname) + $fullname = $nickname; + + if($probe_atom) { + $k = z_fetch_url($atom_feed); + if($k['success']) + $feed_meta = feed_meta($k['body']); + if($feed_meta) { + + // stash any discovered pubsubhubbub hubs in case we need to follow them + // this will save an expensive lookup later + + if($feed_meta['hubs'] && $address) { + set_xconfig($address,'system','push_hubs',$feed_meta['hubs']); } - else { - - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - dbesc($addr), - dbesc($guid), - dbesc($pubkey), - dbesc($addr), - dbesc($profile), - dbesc($vcard['fn']), - dbesc($network), - dbescdate(datetime_convert()) - ); + if($feed_meta['author']['author_name']) { + $fullname = $feed_meta['author']['author_name']; } + if(! $avatar) { + if($feed_meta['author']['author_photo']) + $avatar = $feed_meta['author']['author_photo']; + } + } + } + else { + if($probe_hcard) { + $vcard = scrape_vcard($hcard); + if($vcard) { + logger('vcard: ' . print_r($vcard,true), LOGGER_DATA); + if($vcard['fn']) + $fullname = $vcard['fn']; + if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0)) + $vcard['photo'] = $diaspora_base . '/' . $vcard['photo']; + if(! $avatar) + $avatar = $vcard['photo']; - $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($webbie) - ); - - if(! $r) { - - $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", - dbesc($guid), - dbesc($addr), - dbesc($addr), - dbesc($network), - dbesc(trim($diaspora_base,'/')), - dbesc($hostname), - dbesc($notify), - dbescdate(datetime_convert()) - ); } - $photos = import_xchan_photo($vcard['photo'],$addr); - $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($addr) - ); - return true; + } + } + + if(($profile) && (! $location)) + $location = $profile; + + if($location) { + $m = parse_url($location); + $base = $m['scheme'] . '://' . $m['host']; + $host = $m['host']; + } + + if($diaspora && $diaspora_base && $diaspora_guid) { + if($dfrn) + $network = 'friendica-over-diaspora'; + else + $network = 'diaspora'; + + $base = trim($diaspora_base,'/'); + $notify = $base . '/receive'; + + } + else { + if($gnusoc) { + $network = 'gnusoc'; + $notify = $salmon; } } - return false; -/* - $vcard['fn'] = notags($vcard['fn']); - $vcard['nick'] = str_replace(' ','',notags($vcard['nick'])); - - $result['name'] = $vcard['fn']; - $result['nick'] = $vcard['nick']; - $result['guid'] = $guid; - $result['url'] = $profile; - $result['hostname'] = $hostname; - $result['addr'] = $addr; - $result['batch'] = $batch; - $result['notify'] = $notify; - $result['poll'] = $poll; - $result['request'] = $request; - $result['confirm'] = $confirm; - $result['poco'] = $poco; - $result['photo'] = $vcard['photo']; - $result['priority'] = $priority; - $result['network'] = $network; - $result['alias'] = $alias; - $result['pubkey'] = $pubkey; - - logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG); - - return $result; - -*/ - -/* Sample Diaspora result. - -Array -( - [name] => Mike Macgirvin - [nick] => macgirvin - [guid] => a9174a618f8d269a - [url] => https://joindiaspora.com/u/macgirvin - [hostname] => joindiaspora.com - [addr] => macgirvin@joindiaspora.com - [batch] => - [notify] => https://joindiaspora.com/receive - [poll] => https://joindiaspora.com/public/macgirvin.atom - [request] => - [confirm] => - [poco] => - [photo] => https://joindiaspora.s3.amazonaws.com/uploads/images/thumb_large_fec4e6eef13ae5e56207.jpg - [priority] => - [network] => diaspora - [alias] => - [pubkey] => -----BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtihtyIuRDWkDpCA+I1UaQ -jI4S7k625+A7EEJm+pL2ZVSJxeCKiFeEgHBQENjLMNNm8l8F6blxgQqE6ZJ9Spa7f -tlaXYTRCrfxKzh02L3hR7sNA+JS/nXJaUAIo+IwpIEspmcIRbD9GB7Wv/rr+M28uH -31EeYyDz8QL6InU/bJmnCdFvmEMBQxJOw1ih9tQp7UNJAbUMCje0WYFzBz7sfcaHL -OyYcCOqOCBLdGucUoJzTQ9iDBVzB8j1r1JkIHoEb2moUoKUp+tkCylNfd/3IVELF9 -7w1Qjmit3m50OrJk2DQOXvCW9KQxaQNdpRPSwhvemIt98zXSeyZ1q/YjjOwG0DWDq -AF8aLj3/oQaZndTPy/6tMiZogKaijoxj8xFLuPYDTw5VpKquriVC0z8oxyRbv4t9v -8JZZ9BXqzmayvY3xZGGp8NulrfjW+me2bKh0/df1aHaBwpZdDTXQ6kqAiS2FfsuPN -vg57fhfHbL1yJ4oDbNNNeI0kJTGchXqerr8C20khU/cQ2Xt31VyEZtnTB665Ceugv -kp3t2qd8UpAVKl430S5Quqx2ymfUIdxdW08CEjnoRNEL3aOWOXfbf4gSVaXmPCR4i -LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+ -4afAEhRaaY+MCAwEAAQ== ------END PUBLIC KEY----- - -) -*/ + logger('network: ' . $network); + logger('address: ' . $address); + logger('fullname: ' . $fullname); + logger('pubkey: ' . $pubkey); + logger('location: ' . $location); + + + + // if we have everything we need, let's create the records + + if($network && $address && $fullname && $pubkey && $location) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($address) + ); + if($r) { + $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", + dbesc($fullname), + dbesc($network), + dbesc(datetime_convert()), + dbesc($address) + ); + } + else { + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + dbesc($address), + dbesc(($diaspora_guid) ? $diaspora_guid : $location), + dbesc($pubkey), + dbesc($address), + dbesc($location), + dbesc($fullname), + dbesc($network), + dbescdate(datetime_convert()) + ); + } + + $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($address) + ); + + if(! $r) { + $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", + dbesc(($diaspora_guid) ? $diaspora_guid : $location), + dbesc($address), + dbesc($address), + dbesc($network), + dbesc($base), + dbesc($host), + dbesc($notify), + dbescdate(datetime_convert()) + ); + } + $photos = import_xchan_photo($avatar,$address); + $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", + dbescdate(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($address) + ); + return true; + } + return false; } + function webfinger_rfc7033($webbie,$zot = false) { @@ -1573,7 +1535,7 @@ function fetch_lrdd_template($host) { function fetch_xrd_links($url) { -logger('fetch_xrd_links: ' . $url); + logger('fetch_xrd_links: ' . $url, LOGGER_DEBUG); $redirects = 0; $x = z_fetch_url($url,false,$redirects,array('timeout' => 20)); @@ -1619,6 +1581,10 @@ logger('fetch_xrd_links: ' . $url); } } + if(isset($arr['xrd']['subject'])) { + $links[]['@attributes'] = array('rel' => 'subject' , 'href' => $arr['xrd']['subject']); + } + logger('fetch_xrd_links: ' . print_r($links,true), LOGGER_DATA); return $links; -- cgit v1.2.3