aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/contact_selectors.php22
-rw-r--r--include/crypto.php23
-rw-r--r--include/follow.php48
-rw-r--r--include/group.php16
-rwxr-xr-xinclude/items.php4
-rw-r--r--include/network.php475
-rw-r--r--include/salmon.php196
-rw-r--r--include/widgets.php15
-rw-r--r--include/zot.php6
9 files changed, 321 insertions, 484 deletions
diff --git a/include/contact_selectors.php b/include/contact_selectors.php
index d44bee784..0de4ece00 100644
--- a/include/contact_selectors.php
+++ b/include/contact_selectors.php
@@ -73,16 +73,18 @@ function contact_poll_interval($current, $disabled = false) {
function network_to_name($s) {
$nets = array(
- NETWORK_DFRN => t('Friendica'),
- NETWORK_OSTATUS => t('OStatus'),
- NETWORK_FEED => t('RSS/Atom'),
- NETWORK_MAIL => t('Email'),
- NETWORK_DIASPORA => t('Diaspora'),
- NETWORK_FACEBOOK => t('Facebook'),
- NETWORK_ZOT => t('Zot'),
- NETWORK_LINKEDIN => t('LinkedIn'),
- NETWORK_XMPP => t('XMPP/IM'),
- NETWORK_MYSPACE => t('MySpace'),
+ NETWORK_DFRN => t('Friendica'),
+ NETWORK_FRND => t('Friendica'),
+ NETWORK_OSTATUS => t('OStatus'),
+ NETWORK_GNUSOCIAL => t('GNU-Social'),
+ NETWORK_FEED => t('RSS/Atom'),
+ NETWORK_MAIL => t('Email'),
+ NETWORK_DIASPORA => t('Diaspora'),
+ NETWORK_FACEBOOK => t('Facebook'),
+ NETWORK_ZOT => t('Zot'),
+ NETWORK_LINKEDIN => t('LinkedIn'),
+ NETWORK_XMPP => t('XMPP/IM'),
+ NETWORK_MYSPACE => t('MySpace'),
);
call_hooks('network_to_name', $nets);
diff --git a/include/crypto.php b/include/crypto.php
index 3cddc7581..d82ee5114 100644
--- a/include/crypto.php
+++ b/include/crypto.php
@@ -308,11 +308,33 @@ function metorsa($m,$e) {
return $key;
}
+
+
function salmon_key($pubkey) {
pemtome($pubkey,$m,$e);
return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ;
}
+
+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_DATA);
+ $salmon_key = metopem($m,$e);
+ return $salmon_key;
+
+}
+
+
function z_obscure($s) {
return json_encode(crypto_encapsulate($s,get_config('system','pubkey')));
}
@@ -322,3 +344,4 @@ function z_unobscure($s) {
return $s;
return crypto_unencapsulate(json_decode($s,true),get_config('system','prvkey'));
}
+
diff --git a/include/follow.php b/include/follow.php
index e71b0c713..70e717cfc 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -134,26 +134,29 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$their_perms = 0;
$xchan_hash = '';
-
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1",
dbesc($url),
dbesc($url)
);
-
if(! $r) {
// attempt network auto-discovery
- if(strpos($url,'@') && (! $is_http)) {
- $d = discover_by_webbie($url);
- }
- elseif($is_http) {
- if(get_config('system','feed_contacts'))
+
+ $d = discover_by_webbie($url);
+
+ if((! $d) && ($is_http)) {
+
+ // try RSS discovery
+
+ if(get_config('system','feed_contacts')) {
$d = discover_by_url($url);
+ }
else {
$result['message'] = t('Protocol disabled.');
return $result;
}
}
+
if($d) {
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1",
dbesc($url),
@@ -161,6 +164,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
);
}
}
+
+ // if discovery was a success we should have an xchan record in $r
+
if($r) {
$xchan = $r[0];
$xchan_hash = $r[0]['xchan_hash'];
@@ -187,28 +193,13 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
}
$singleton = intval($x['singleton']);
- if((local_channel()) && $uid == local_channel()) {
- $aid = get_account_id();
- $hash = get_observer_hash();
- $ch = $a->get_channel();
- $default_group = $ch['channel_default_group'];
- }
- else {
- $r = q("select * from channel where channel_id = %d limit 1",
- intval($uid)
- );
- if(! $r) {
- $result['message'] = t('local account not found.');
- return $result;
- }
- $aid = $r[0]['channel_account_id'];
- $hash = $r[0]['channel_hash'];
- $default_group = $r[0]['channel_default_group'];
- }
-
+ $aid = $channel['channel_account_id'];
+ $hash = get_observer_hash();
+ $default_group = $channel['channel_default_group'];
- if($is_http) {
+ if($xchan['xchan_network'] === 'rss') {
+ // check service class feed limits
$r = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ",
intval($aid)
@@ -232,7 +223,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
intval($uid)
);
-
if($r) {
$abook_instance = $r[0]['abook_instance'];
@@ -282,7 +272,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
proc_run('php', 'include/notifier.php', 'permission_create', $result['abook']['abook_id']);
}
- $arr = array('channel_id' => $uid, 'abook' => $result['abook']);
+ $arr = array('channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']);
call_hooks('follow', $arr);
diff --git a/include/group.php b/include/group.php
index 22f221059..748ec0c13 100644
--- a/include/group.php
+++ b/include/group.php
@@ -211,6 +211,22 @@ function group_get_members($gid) {
return $ret;
}
+function group_get_members_xchan($gid) {
+ $ret = array();
+ if(intval($gid)) {
+ $r = q("SELECT xchan FROM group_member WHERE gid = %d AND uid = %d",
+ intval($gid),
+ intval(local_channel())
+ );
+ if(count($r)) {
+ foreach($r as $rr) {
+ $ret[] = $rr['xchan'];
+ }
+ }
+ }
+ return $ret;
+}
+
function mini_group_select($uid,$group = '') {
$grps = array();
diff --git a/include/items.php b/include/items.php
index c3a0b82d2..879f8ea12 100755
--- a/include/items.php
+++ b/include/items.php
@@ -4214,7 +4214,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) {
$parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']);
- $o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
+ $o .= '<thr:in-reply-to ref="' . z_root() . '/display/' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
}
if(activity_match($item['obj_type'],ACTIVITY_OBJ_EVENT) && activity_match($item['verb'],ACTIVITY_POST)) {
@@ -4232,7 +4232,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
$o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n";
}
- $o .= '<id>' . xmlify($item['mid']) . '</id>' . "\r\n";
+ $o .= '<id>' . z_root() . '/display/' . xmlify($item['mid']) . '</id>' . "\r\n";
$o .= '<published>' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '</published>' . "\r\n";
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
diff --git a/include/network.php b/include/network.php
index 7d41a7eb7..e7d341321 100644
--- a/include/network.php
+++ b/include/network.php
@@ -185,9 +185,11 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
if($ciphers)
@curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
- if(x($opts,'headers'))
+ if(x($opts,'headers')) {
@curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
-
+logger('headers: ' . print_r($opts['headers'],true) . 'redir: ' . $redirects);
+ }
+
if(x($opts,'nobody'))
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
@@ -236,6 +238,21 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
$base = substr($base,strlen($chunk));
}
+ // would somebody take lighttpd and just shoot it?
+
+ if($http_code == 417) {
+ curl_close($ch);
+ if($opts) {
+ if($opts['headers'])
+ $opts['headers'][] = 'Expect:';
+ else
+ $opts['headers'] = array('Expect:');
+ }
+ else
+ $opts = array('headers' => array('Expect:'));
+ return z_post_url($url,$params,++$redirects,$opts);
+ }
+
if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
$matches = array();
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
@@ -1044,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;
@@ -1077,7 +1078,6 @@ function discover_by_webbie($webbie) {
$diaspora_base = '';
$diaspora_guid = '';
$diaspora_key = '';
- $dfrn = false;
$webbie = strtolower($webbie);
@@ -1085,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'])
@@ -1098,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']);
@@ -1105,6 +1112,7 @@ function discover_by_webbie($webbie) {
}
if($link['rel'] == 'salmon') {
$has_salmon = true;
+ $salmon = $link['href'];
}
if($link['rel'] == 'http://schemas.google.com/g/2010#updates-from') {
$atom_feed = $link['href'];
@@ -1113,82 +1121,40 @@ function discover_by_webbie($webbie) {
}
}
-
- logger('webfing: ' . print_r($x,true));
+ 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']);
- 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())
- );
- }
+ $probe_atom = false;
+ $probe_old = false;
+ $probe_hcard = false;
- $r = q("select * from hubloc where hubloc_hash = '%s' limit 1",
- dbesc($addr)
- );
+ $address = '';
+ $location = '';
+ $nickname = '';
+ $fullname = '';
+ $avatar = '';
+ $pubkey = '';
- 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;
+ 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'];
- }
- }
- else {
+ if(! $x)
+ $probe_old = true;
+ if($probe_old) {
$x = old_webfinger($webbie);
if($x) {
logger('old_webfinger: ' . print_r($x,true));
@@ -1221,174 +1187,195 @@ 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)
- );
+ }
+
+ 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) {
- // 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)
- );
+ // 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']);
+ set_xconfig($address,'system','feed_url',$atom_feed);
}
- 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) {
@@ -1473,8 +1460,8 @@ function find_webfinger_location($j,$rhs) {
function match_webfinger_location($s,$h) {
- // GNU-social and the older StatusNet
- if(preg_match('|' . $h . '/user/([0-9]*?)$|',$s))
+ // GNU-social and the older StatusNet - the $host/user/123 form doesn't work
+ if(preg_match('|' . $h . '/index.php/user/([0-9]*?)$|',$s))
return $s;
// Redmatrix / hubzilla
if(preg_match('|' . $h . '/channel/|',$s))
@@ -1549,7 +1536,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));
@@ -1595,6 +1582,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;
diff --git a/include/salmon.php b/include/salmon.php
deleted file mode 100644
index 737d1f0d0..000000000
--- a/include/salmon.php
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-
-require_once('include/crypto.php');
-
-function get_salmon_key($uri,$keyhash) {
- $ret = array();
-
- logger('Fetching salmon key for ' . $uri, LOGGER_DEBUG, LOG_INFO);
-
- $x = webfinger_rfc7033($uri,true);
-
- logger('webfinger returns: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
-
- if($x && array_key_exists('links',$x) && $x['links']) {
- foreach($x['links'] as $link) {
- if(array_key_exists('rel',$link) && $link['rel'] === 'magic-public-key') {
- $ret[] = $link['href'];
- }
- }
- }
-
- else {
- $arr = old_webfinger($uri);
-
- logger('old webfinger returns: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
-
- if(is_array($arr)) {
- foreach($arr as $a) {
- if($a['@attributes']['rel'] === 'magic-public-key') {
- $ret[] = $a['@attributes']['href'];
- }
- }
- }
- else {
- return '';
- }
- }
-
- // We have found at least one key URL
- // If it's inline, parse it - otherwise get the key
-
- if(count($ret)) {
- for($x = 0; $x < count($ret); $x ++) {
- if(substr($ret[$x],0,5) === 'data:') {
- $ret[$x] = convert_salmon_key($ret[$x]);
- }
- }
- }
-
-
- logger('Key located: ' . print_r($ret,true), LOGGER_DEBUG, LOG_INFO);
-
- if(count($ret) == 1) {
-
- // We only found one one key so we don't care if the hash matches.
- // If it's the wrong key we'll find out soon enough because
- // message verification will fail. This also covers some older
- // software which don't supply a keyhash. As long as they only
- // have one key we'll be right.
-
- return $ret[0];
- }
- else {
- foreach($ret as $a) {
- $hash = base64url_encode(hash('sha256',$a));
- if($hash == $keyhash)
- return $a;
- }
- }
-
- return '';
-}
-
-
-
-function slapper($owner,$url,$slap) {
-
- // does contact have a salmon endpoint?
-
- if(! strlen($url))
- return;
-
-
- if(! $owner['channel_prvkey']) {
- logger(sprintf("channel '%s' (%d) does not have a salmon private key. Send failed.",
- $owner['channel_address'],$owner['channel_id']));
- return;
- }
-
- logger('slapper called for ' .$url . '. Data: ' . $slap, LOGGER_DATA, LOG_DEBUG);
-
- // create a magic envelope
-
- $data = base64url_encode($slap);
- $data_type = 'application/atom+xml';
- $encoding = 'base64url';
- $algorithm = 'RSA-SHA256';
- $keyhash = base64url_encode(hash('sha256',salmon_key($owner['channel_pubkey'])),true);
-
- // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
-
- $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
-
- $signature = base64url_encode(rsa_sign(str_replace('=','',$data . $precomputed),$owner['channel_prvkey']));
-
- $signature2 = base64url_encode(rsa_sign($data . $precomputed,$owner['channel_prvkey']));
-
- $signature3 = base64url_encode(rsa_sign($data,$owner['channel_prvkey']));
-
- $salmon_tpl = get_markup_template('magicsig.tpl');
-
- $salmon = replace_macros($salmon_tpl,array(
- '$data' => $data,
- '$encoding' => $encoding,
- '$algorithm' => $algorithm,
- '$keyhash' => $keyhash,
- '$signature' => $signature
- ));
-
- // slap them
-
- $redirects = 0;
-
- $ret = z_post_url($url,$salmon, $redirects, array('headers' => array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon))
- ));
-
-
- $return_code = $ret['return_code'];
-
- // check for success, e.g. 2xx
-
- if($return_code > 299) {
-
- logger('compliant salmon failed. Falling back to status.net hack2');
-
- // Entirely likely that their salmon implementation is
- // non-compliant. Let's try once more, this time only signing
- // the data, without stripping '=' chars
-
- $salmon = replace_macros($salmon_tpl,array(
- '$data' => $data,
- '$encoding' => $encoding,
- '$algorithm' => $algorithm,
- '$keyhash' => $keyhash,
- '$signature' => $signature2
- ));
-
- $redirects = 0;
-
- $ret = z_post_url($url,$salmon, $redirects, array('headers' => array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon))
- ));
-
-
- $return_code = $ret['return_code'];
-
- if($return_code > 299) {
-
- logger('compliant salmon failed. Falling back to status.net hack3');
-
- // Entirely likely that their salmon implementation is
- // non-compliant. Let's try once more, this time only signing
- // the data, without the precomputed blob
-
- $salmon = replace_macros($salmon_tpl,array(
- '$data' => $data,
- '$encoding' => $encoding,
- '$algorithm' => $algorithm,
- '$keyhash' => $keyhash,
- '$signature' => $signature3
- ));
-
- $redirects = 0;
-
- $ret = z_post_url($url,$salmon, $redirects, array('headers' => array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon))
- ));
-
-
- $return_code = $ret['return_code'];
- }
- }
- logger('slapper for ' . $url . ' returned ' . $return_code);
-
- if(! $return_code)
- return(-1);
- if(($return_code == 503) && (stristr($ret['header'],'retry-after')))
- return(-1);
-
- return ((($return_code >= 200) && ($return_code < 300)) ? 0 : 1);
-}
-
diff --git a/include/widgets.php b/include/widgets.php
index 65c745a05..deb514915 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -1314,7 +1314,7 @@ function widget_admin($arr) {
$aside = array(
'site' => array(z_root() . '/admin/site/', t('Site'), 'site'),
- 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users'),
+ 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users', 'pending-update', t('Member registrations waiting for confirmation')),
'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'),
'security' => array(z_root() . '/admin/security/', t('Security'), 'security'),
'features' => array(z_root() . '/admin/features/', t('Features'), 'features'),
@@ -1330,24 +1330,29 @@ function widget_admin($arr) {
$r = q("SELECT * FROM addon WHERE plugin_admin = 1");
- $aside['plugins_admin'] = array();
+ $plugins = array();
if($r) {
foreach ($r as $h){
$plugin = $h['name'];
- $aside['plugins_admin'][] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin');
+ $plugins[] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin');
// temp plugins with admin
$a->plugins_admin[] = $plugin;
}
}
- $aside['logs'] = array(z_root() . '/admin/logs/', t('Logs'), 'logs');
+ $logs = array(z_root() . '/admin/logs/', t('Logs'), 'logs');
+
+ $arr = array('links' => $aside,'plugins' => $plugins,'logs' => $logs);
+ call_hooks('admin_aside',$arr);
$o .= replace_macros(get_markup_template('admin_aside.tpl'), array(
'$admin' => $aside,
'$admtxt' => t('Admin'),
'$plugadmtxt' => t('Plugin Features'),
+ '$plugins' => $plugins,
'$logtxt' => t('Logs'),
- '$h_pending' => t('User registrations waiting for confirmation'),
+ '$logs' => $logs,
+ '$h_pending' => t('Member registrations waiting for confirmation'),
'$admurl'=> z_root() . '/admin/'
));
diff --git a/include/zot.php b/include/zot.php
index cff9e1810..d8cae3954 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -2278,6 +2278,12 @@ function check_location_move($sender_hash,$locations) {
dbesc($sender_hash)
);
+ // federation plugins may wish to notify connections
+ // of the move on singleton networks
+
+ $arr = array('channel' => $r[0],'locations' => $locations);
+ call_hooks('location_move',$arr);
+
}
}