diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/contact_selectors.php | 22 | ||||
-rw-r--r-- | include/crypto.php | 23 | ||||
-rw-r--r-- | include/follow.php | 48 | ||||
-rw-r--r-- | include/group.php | 16 | ||||
-rwxr-xr-x | include/items.php | 4 | ||||
-rw-r--r-- | include/network.php | 475 | ||||
-rw-r--r-- | include/salmon.php | 196 | ||||
-rw-r--r-- | include/widgets.php | 15 | ||||
-rw-r--r-- | include/zot.php | 6 |
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); + } } |