lots of work on federated channel discovery
This commit is contained in:
parent
4188419b30
commit
38eb79705e
@ -1 +0,0 @@
|
||||
[h2]discover_by_webbie[/h2]
|
14
doc/hook/discover_channel_webfinger.bb
Normal file
14
doc/hook/discover_channel_webfinger.bb
Normal file
@ -0,0 +1,14 @@
|
||||
[h2]discover_channel_webfinger[/h2]
|
||||
|
||||
Called after performing channel discovery using RFC7033 webfinger and where the channel is not recognised as zot.
|
||||
|
||||
Passed an array:
|
||||
|
||||
address: URL or address that is being discovered
|
||||
success: set to true if the plugin discovers something
|
||||
webfinger: array of webfinger links (output of webfinger_rfc7033())
|
||||
|
||||
|
||||
if your plugin indicates success you are expected to generate and populate an xchan (and hubloc) record prior to returning.
|
||||
|
||||
|
@ -127,7 +127,7 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/directory_item]directory_item[/zrl]
|
||||
Called when generating a directory listing for display
|
||||
|
||||
[zrl=[baseurl]/help/hook/discover_by_webbie]discover_by_webbie[/zrl]
|
||||
[zrl=[baseurl]/help/hook/discover_channel_webfinger]discover_channel_webfinger[/zrl]
|
||||
Called when performing a webfinger lookup
|
||||
|
||||
[zrl=[baseurl]/help/hook/display_item]display_item[/zrl]
|
||||
|
@ -175,7 +175,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
|
||||
return $result;
|
||||
}
|
||||
|
||||
$x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => 1, 'singleton' => 0);
|
||||
$allowed = ($r[0]['xchan_network'] === 'zot' || $r[0]['xchan_network'] === 'rss') ? 1 : 0);
|
||||
|
||||
$x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => $allowed, 'singleton' => 0);
|
||||
|
||||
call_hooks('follow_allow',$x);
|
||||
|
||||
|
@ -4069,29 +4069,65 @@ function process_salmon_feed($xml, $importer) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an xml (atom) feed, find any links with rel="hub" and return an array of href links or false
|
||||
* Given an xml (atom) feed, find author and hub links
|
||||
*/
|
||||
|
||||
|
||||
function find_hubs($xml) {
|
||||
function feed_meta($xml) {
|
||||
require_once('library/simplepie/simplepie.inc');
|
||||
|
||||
$ret = array();
|
||||
|
||||
if(! strlen($xml)) {
|
||||
logger('empty input');
|
||||
return false;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$feed = new SimplePie();
|
||||
$feed->set_raw_data($xml);
|
||||
$feed->init();
|
||||
|
||||
if($feed->error())
|
||||
if($feed->error()) {
|
||||
logger('Error parsing XML: ' . $feed->error());
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$hubs = $feed->get_links('hub');
|
||||
logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA);
|
||||
$ret['hubs'] = $feed->get_links('hub');
|
||||
|
||||
return $hubs;
|
||||
// logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA);
|
||||
|
||||
$author = array();
|
||||
|
||||
$found_author = $feed->get_author();
|
||||
if($found_author) {
|
||||
$author['author_name'] = unxmlify($found_author->get_name());
|
||||
$author['author_link'] = unxmlify($found_author->get_link());
|
||||
|
||||
$rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
|
||||
logger('rawauthor: ' . print_r($rawauthor,true));
|
||||
|
||||
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
|
||||
$base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
|
||||
foreach($base as $link) {
|
||||
if(!x($author, 'author_photo') || ! $author['author_photo']) {
|
||||
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
|
||||
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data'])
|
||||
$author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(substr($author['author_link'],-1,1) == '/')
|
||||
$author['author_link'] = substr($author['author_link'],0,-1);
|
||||
|
||||
$ret['author'] = $author;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1043,75 +1043,184 @@ 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;
|
||||
$diaspora = false;
|
||||
$gnusoc = false;
|
||||
|
||||
$has_salmon = false;
|
||||
$salmon_key = false;
|
||||
$atom_feed = false;
|
||||
$diaspora_base = '';
|
||||
$diaspora_guid = '';
|
||||
$diaspora_key = '';
|
||||
$dfrn = false;
|
||||
|
||||
$webbie = strtolower($webbie);
|
||||
|
||||
$x = webfinger_rfc7033($webbie,true);
|
||||
if($x && array_key_exists('links',$x) && $x['links']) {
|
||||
foreach($x['links'] as $link) {
|
||||
if(array_key_exists('rel',$link) && $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'])
|
||||
$i = import_xchan($x['zot']);
|
||||
else {
|
||||
$z = z_fetch_url($link['href']);
|
||||
if($z['success']) {
|
||||
$j = json_decode($z['body'],true);
|
||||
$i = import_xchan($j);
|
||||
return true;
|
||||
if(array_key_exists('rel',$link)) {
|
||||
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'])
|
||||
$i = import_xchan($x['zot']);
|
||||
else {
|
||||
$z = z_fetch_url($link['href']);
|
||||
if($z['success']) {
|
||||
$j = json_decode($z['body'],true);
|
||||
$i = import_xchan($j);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($link['rel'] == 'magic-public-key') {
|
||||
if(substr($link['href'],0,5) === 'data:') {
|
||||
$salmon_key = convert_salmon_key($link['href']);
|
||||
}
|
||||
}
|
||||
if($link['rel'] == 'salmon') {
|
||||
$has_salmon = true;
|
||||
}
|
||||
if($link['rel'] == 'http://schemas.google.com/g/2010#updates-from') {
|
||||
$atom_feed = $link['href'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$arr = array('address' => $webbie, 'success' => false);
|
||||
call_hooks('discover_by_webbie', $arr);
|
||||
|
||||
logger('webfing: ' . print_r($x,true));
|
||||
|
||||
$arr = array('address' => $webbie, 'success' => false, 'webfinger' => $x);
|
||||
call_hooks('discover_channel_webfinger', $arr);
|
||||
if($arr['success'])
|
||||
return true;
|
||||
|
||||
$result = array();
|
||||
$network = null;
|
||||
$diaspora = false;
|
||||
if($salmon_key && $has_salmon && $atom_feed) {
|
||||
|
||||
$gnusoc = true;
|
||||
$addr = $x['address'];
|
||||
|
||||
$diaspora_base = '';
|
||||
$diaspora_guid = '';
|
||||
$diaspora_key = '';
|
||||
$dfrn = false;
|
||||
$m = parse_url($x['location']);
|
||||
|
||||
$x = old_webfinger($webbie);
|
||||
if($x) {
|
||||
logger('old_webfinger: ' . print_r($x,true));
|
||||
foreach($x as $link) {
|
||||
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
|
||||
$dfrn = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'salmon')
|
||||
$notify = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === NAMESPACE_FEED)
|
||||
$poll = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
|
||||
$hcard = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
|
||||
$profile = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0')
|
||||
$poco = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') {
|
||||
$diaspora_base = unamp($link['@attributes']['href']);
|
||||
$diaspora = true;
|
||||
$k = z_fetch_url($atom_feed);
|
||||
if($k['success'])
|
||||
$feed_meta = feed_meta($k['body']);
|
||||
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)
|
||||
);
|
||||
}
|
||||
if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') {
|
||||
$diaspora_guid = unamp($link['@attributes']['href']);
|
||||
$diaspora = true;
|
||||
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())
|
||||
);
|
||||
}
|
||||
if($link['@attributes']['rel'] === 'diaspora-public-key') {
|
||||
$diaspora_key = base64_decode(unamp($link['@attributes']['href']));
|
||||
if(strstr($diaspora_key,'RSA '))
|
||||
$pubkey = rsatopem($diaspora_key);
|
||||
else
|
||||
$pubkey = $diaspora_key;
|
||||
$diaspora = true;
|
||||
|
||||
$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 {
|
||||
|
||||
$x = old_webfinger($webbie);
|
||||
if($x) {
|
||||
logger('old_webfinger: ' . print_r($x,true));
|
||||
foreach($x as $link) {
|
||||
if($link['@attributes']['rel'] === NAMESPACE_DFRN)
|
||||
$dfrn = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'salmon')
|
||||
$notify = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === NAMESPACE_FEED)
|
||||
$poll = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
|
||||
$hcard = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
|
||||
$profile = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0')
|
||||
$poco = unamp($link['@attributes']['href']);
|
||||
if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') {
|
||||
$diaspora_base = unamp($link['@attributes']['href']);
|
||||
$diaspora = true;
|
||||
}
|
||||
if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') {
|
||||
$diaspora_guid = unamp($link['@attributes']['href']);
|
||||
$diaspora = true;
|
||||
}
|
||||
if($link['@attributes']['rel'] === 'diaspora-public-key') {
|
||||
$diaspora_key = base64_decode(unamp($link['@attributes']['href']));
|
||||
if(strstr($diaspora_key,'RSA '))
|
||||
$pubkey = rsatopem($diaspora_key);
|
||||
else
|
||||
$pubkey = $diaspora_key;
|
||||
$diaspora = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1167,7 +1276,7 @@ function discover_by_webbie($webbie) {
|
||||
}
|
||||
else {
|
||||
|
||||
$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
|
||||
$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),
|
||||
@ -1175,7 +1284,6 @@ function discover_by_webbie($webbie) {
|
||||
dbesc($profile),
|
||||
dbesc($vcard['fn']),
|
||||
dbesc($network),
|
||||
dbesc(z_root()),
|
||||
dbescdate(datetime_convert())
|
||||
);
|
||||
}
|
||||
@ -1199,7 +1307,7 @@ function discover_by_webbie($webbie) {
|
||||
}
|
||||
$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('UTC','UTC',$arr['photo_updated'])),
|
||||
dbescdate(datetime_convert()),
|
||||
dbesc($photos[0]),
|
||||
dbesc($photos[1]),
|
||||
dbesc($photos[2]),
|
||||
@ -1209,7 +1317,7 @@ function discover_by_webbie($webbie) {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1278,10 +1386,6 @@ LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+
|
||||
)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1308,13 +1412,89 @@ function webfinger_rfc7033($webbie,$zot = false) {
|
||||
|
||||
$s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''));
|
||||
|
||||
if($s['success'])
|
||||
if($s['success']) {
|
||||
$j = json_decode($s['body'],true);
|
||||
|
||||
// We could have a number of URL aliases and webbies
|
||||
// make an executive decision about the most likely "best" of each
|
||||
// by comparing against some examples from known networks we're likely to encounter.
|
||||
// Otherwise we have to store every alias that we may ever encounter and
|
||||
// validate every URL we ever find against every possible alias
|
||||
|
||||
// @fixme pump.io is going to be a real bugger since it doesn't return subject or aliases
|
||||
// or provide lookup by url
|
||||
|
||||
$j['address'] = find_webfinger_address($j,$rhs);
|
||||
$j['location'] = find_webfinger_location($j,$rhs);
|
||||
if($j['address'])
|
||||
$j['nickname'] = substr($j['address'],0,strpos($j['address'],'@'));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return($j);
|
||||
}
|
||||
|
||||
function find_webfinger_address($j,$rhs) {
|
||||
if(is_array($j) && ($j)) {
|
||||
if(strpos($j['subject'],'acct:') !== false && strpos($j['subject'],'@' . $rhs))
|
||||
return str_replace('acct:','',$j['subject']);
|
||||
if($j['aliases']) {
|
||||
foreach($j['aliases'] as $alias) {
|
||||
if(strpos($alias,'acct:') !== false && strpos($alias,'@' . $rhs)) {
|
||||
return str_replace('acct:','',$alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
function find_webfinger_location($j,$rhs) {
|
||||
if(is_array($j) && ($j)) {
|
||||
if(strpos($j['subject'],'http') === 0) {
|
||||
$x = match_webfinger_location($j['subject'],$rhs);
|
||||
if($x)
|
||||
return $x;
|
||||
}
|
||||
if($j['aliases']) {
|
||||
foreach($j['aliases'] as $alias) {
|
||||
if(strpos($alias,'http') === 0) {
|
||||
$x = match_webfinger_location($alias,$rhs);
|
||||
if($x)
|
||||
return($x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function match_webfinger_location($s,$h) {
|
||||
|
||||
// GNU-social and the older StatusNet
|
||||
if(preg_match('|' . $h . '/user/([0-9]*?)$|',$s))
|
||||
return $s;
|
||||
// Redmatrix / hubzilla
|
||||
if(preg_match('|' . $h . '/channel/|',$s))
|
||||
return $s;
|
||||
// Friendica
|
||||
if(preg_match('|' . $h . '/profile/|',$s))
|
||||
return $s;
|
||||
|
||||
$arr = array('test' => $s, 'host' => $h, 'success' => false);
|
||||
call_hooks('match_webfinger_location',$arr);
|
||||
if($arr['success'])
|
||||
return $s;
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function old_webfinger($webbie) {
|
||||
|
||||
|
@ -73,13 +73,15 @@ function wfinger_init(&$a) {
|
||||
|
||||
$result['aliases'] = array();
|
||||
|
||||
$result['properties'] = array('http://webfinger.net/ns/name' => $r[0]['channel_name']);
|
||||
$result['properties'] = array(
|
||||
'http://webfinger.net/ns/name' => $r[0]['channel_name'],
|
||||
'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name']
|
||||
);
|
||||
|
||||
foreach($aliases as $alias)
|
||||
if($alias != $resource)
|
||||
$result['aliases'][] = $alias;
|
||||
|
||||
|
||||
$result['links'] = array(
|
||||
|
||||
array(
|
||||
|
@ -1 +1 @@
|
||||
2016-03-15.1336H
|
||||
2016-03-16.1337H
|
||||
|
Reference in New Issue
Block a user